1 # include <errno.h> 2 # include "sendmail.h" 3 4 #ifndef DAEMON 5 SCCSID(@(#)daemon.c 3.16 06/26/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.16 06/26/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 */ 79 80 InChannel = fdopen(port, "r"); 81 OutChannel = fdopen(port, "w"); 82 initsys(); 83 # ifdef DEBUG 84 if (Debug > 1) 85 printf("getreq: returning\n"); 86 # endif DEBUG 87 return; 88 } 89 90 /* 91 ** PARENT -- wait for child to terminate. 92 ** Perhaps we should allow concurrent processing? 93 */ 94 95 # ifdef DEBUG 96 if (Debug > 1) 97 { 98 sleep(2); 99 printf("getreq: parent waiting\n"); 100 } 101 # endif DEBUG 102 103 /* close the port so that others will hang (for a while) */ 104 (void) close(port); 105 106 /* pick up old zombies; implement load limiting */ 107 numconnections++; 108 while (wait3(&status, numconnections < MAXCONNS ? WNOHANG : 0, 0) > 0) 109 numconnections--; 110 } 111 } 112 /* 113 ** GETCONNECTION -- make a connection with the outside world 114 ** 115 ** Parameters: 116 ** none. 117 ** 118 ** Returns: 119 ** The port for mail traffic. 120 ** 121 ** Side Effects: 122 ** Waits for a connection. 123 */ 124 125 #define IPPORT_PLAYPORT 3055 /* random number */ 126 127 struct sockaddr_in SendmailAddress = { AF_INET, IPPORT_SMTP }; 128 129 getconnection() 130 { 131 register int s; 132 struct sockaddr otherend; 133 134 /* 135 ** Set up the address for the mailer. 136 */ 137 138 SendmailAddress.sin_addr.s_addr = 0; 139 SendmailAddress.sin_port = IPPORT_SMTP; 140 # ifdef DEBUG 141 if (Debug > 0) 142 SendmailAddress.sin_port = IPPORT_PLAYPORT; 143 # endif DEBUG 144 SendmailAddress.sin_port = htons(SendmailAddress.sin_port); 145 146 /* 147 ** Try to actually open the connection. 148 */ 149 150 # ifdef DEBUG 151 if (Debug) 152 printf("getconnection\n"); 153 # endif DEBUG 154 155 s = socket(SOCK_STREAM, 0, &SendmailAddress, SO_ACCEPTCONN); 156 if (s < 0) 157 { 158 sleep(10); 159 return (s); 160 } 161 162 # ifdef DEBUG 163 if (Debug) 164 printf("getconnection: %d\n", s); 165 # endif DEBUG 166 if (accept(s, &otherend) < 0) 167 { 168 syserr("accept"); 169 (void) close(s); 170 return (-1); 171 } 172 173 return (s); 174 } 175 /* 176 ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 177 ** 178 ** Parameters: 179 ** host -- the name of the host. 180 ** port -- the port number to connect to. 181 ** outfile -- a pointer to a place to put the outfile 182 ** descriptor. 183 ** infile -- ditto for infile. 184 ** 185 ** Returns: 186 ** An exit code telling whether the connection could be 187 ** made and if not why not. 188 ** 189 ** Side Effects: 190 ** none. 191 */ 192 193 makeconnection(host, port, outfile, infile) 194 char *host; 195 u_short port; 196 FILE **outfile; 197 FILE **infile; 198 { 199 register int s; 200 201 /* 202 ** Set up the address for the mailer. 203 */ 204 205 if ((SendmailAddress.sin_addr.s_addr = rhost(&host)) == -1) 206 return (EX_NOHOST); 207 if (port == 0) 208 port = IPPORT_SMTP; 209 SendmailAddress.sin_port = htons(port); 210 211 /* 212 ** Try to actually open the connection. 213 */ 214 215 # ifdef DEBUG 216 if (Debug) 217 printf("makeconnection (%s)\n", host); 218 # endif DEBUG 219 220 s = socket(SOCK_STREAM, 0, (struct sockaddr_in *) 0, 0); 221 if (s < 0) 222 { 223 syserr("makeconnection: no socket"); 224 goto failure; 225 } 226 227 # ifdef DEBUG 228 if (Debug) 229 printf("makeconnection: %d\n", s); 230 # endif DEBUG 231 if (connect(s, &SendmailAddress) < 0) 232 { 233 /* failure, decide if temporary or not */ 234 failure: 235 switch (errno) 236 { 237 case EISCONN: 238 case ETIMEDOUT: 239 case EINPROGRESS: 240 case EALREADY: 241 case EADDRINUSE: 242 case ENETDOWN: 243 case ENETRESET: 244 case ENOBUFS: 245 case ECONNREFUSED: 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