17aa493c5Seric # include <errno.h> 27fa39d90Seric # include "sendmail.h" 37fa39d90Seric 4d0a9e852Seric #ifndef DAEMON 5*61e4310fSeric SCCSID(@(#)daemon.c 3.22 08/08/82 (w/o daemon mode)); 6d0a9e852Seric #else 7d0a9e852Seric 8d0a9e852Seric # include <sys/socket.h> 9d0a9e852Seric # include <net/in.h> 102554d49fSeric # include <wait.h> 11d0a9e852Seric 12*61e4310fSeric SCCSID(@(#)daemon.c 3.22 08/08/82 (with daemon mode)); 137fa39d90Seric 147fa39d90Seric /* 157fa39d90Seric ** DAEMON.C -- routines to use when running as a daemon. 1647b12ae1Seric ** 1747b12ae1Seric ** This entire file is highly dependent on the 4.2 BSD 1847b12ae1Seric ** interprocess communication primitives. No attempt has 1947b12ae1Seric ** been made to make this file portable to Version 7, 2047b12ae1Seric ** Version 6, MPX files, etc. If you should try such a 2147b12ae1Seric ** thing yourself, I recommend chucking the entire file 2247b12ae1Seric ** and starting from scratch. Basic semantics are: 2347b12ae1Seric ** 2447b12ae1Seric ** getrequests() 2547b12ae1Seric ** Opens a port and initiates a connection. 2647b12ae1Seric ** Returns in a child. Must set InChannel and 2747b12ae1Seric ** OutChannel appropriately. 2847b12ae1Seric ** makeconnection(host, port, outfile, infile) 2947b12ae1Seric ** Make a connection to the named host on the given 3047b12ae1Seric ** port. Set *outfile and *infile to the files 3147b12ae1Seric ** appropriate for communication. Returns zero on 3247b12ae1Seric ** success, else an exit status describing the 3347b12ae1Seric ** error. 3447b12ae1Seric ** 3547b12ae1Seric ** The semantics of both of these should be clean. 367fa39d90Seric */ 377fa39d90Seric /* 387fa39d90Seric ** GETREQUESTS -- open mail IPC port and get requests. 397fa39d90Seric ** 407fa39d90Seric ** Parameters: 417fa39d90Seric ** none. 427fa39d90Seric ** 437fa39d90Seric ** Returns: 447fa39d90Seric ** none. 457fa39d90Seric ** 467fa39d90Seric ** Side Effects: 477fa39d90Seric ** Waits until some interesting activity occurs. When 487fa39d90Seric ** it does, a child is created to process it, and the 497fa39d90Seric ** parent waits for completion. Return from this 507fa39d90Seric ** routine is always in the child. 517fa39d90Seric */ 527fa39d90Seric 532554d49fSeric # define MAXCONNS 4 /* maximum simultaneous sendmails */ 542554d49fSeric 557fa39d90Seric getrequests() 567fa39d90Seric { 572554d49fSeric union wait status; 582554d49fSeric int numconnections = 0; 592554d49fSeric 60eb889047Seric for (;;) 61eb889047Seric { 62a8268164Seric register int pid; 63d0a9e852Seric register int port; 64eb889047Seric 65a8268164Seric /* 66a8268164Seric ** Wait for a connection. 67eb889047Seric */ 68eb889047Seric 69d0a9e852Seric while ((port = getconnection()) < 0) 70d0a9e852Seric { 71d0a9e852Seric syserr("getrequests: getconnection failed"); 7247b12ae1Seric finis(); 73d0a9e852Seric } 74d0a9e852Seric 75d0a9e852Seric /* 76d0a9e852Seric ** Create a subprocess to process the mail. 77d0a9e852Seric */ 78d0a9e852Seric 79d0a9e852Seric # ifdef DEBUG 80*61e4310fSeric if (tTd(15, 2)) 81d0a9e852Seric printf("getrequests: forking (port = %d)\n", port); 82d0a9e852Seric # endif DEBUG 83eb889047Seric 84a8268164Seric pid = fork(); 85a8268164Seric if (pid < 0) 86a8268164Seric { 87a8268164Seric syserr("daemon: cannot fork"); 88a8268164Seric sleep(10); 89b7db1904Seric (void) close(port); 90a8268164Seric continue; 91a8268164Seric } 92a8268164Seric 93a8268164Seric if (pid == 0) 94a8268164Seric { 95a8268164Seric /* 96a8268164Seric ** CHILD -- return to caller. 97a8268164Seric ** Verify calling user id if possible here. 98a8268164Seric */ 99a8268164Seric 100d0a9e852Seric InChannel = fdopen(port, "r"); 101d0a9e852Seric OutChannel = fdopen(port, "w"); 102d0a9e852Seric # ifdef DEBUG 103*61e4310fSeric if (tTd(15, 2)) 104d0a9e852Seric printf("getreq: returning\n"); 105d0a9e852Seric # endif DEBUG 106a8268164Seric return; 107a8268164Seric } 108a8268164Seric 109a8268164Seric /* 110a8268164Seric ** PARENT -- wait for child to terminate. 111a8268164Seric ** Perhaps we should allow concurrent processing? 112a8268164Seric */ 113a8268164Seric 114d0a9e852Seric # ifdef DEBUG 115*61e4310fSeric if (tTd(15, 2)) 116d0a9e852Seric { 117d0a9e852Seric sleep(2); 118d0a9e852Seric printf("getreq: parent waiting\n"); 119d0a9e852Seric } 120d0a9e852Seric # endif DEBUG 121d0a9e852Seric 1222554d49fSeric /* close the port so that others will hang (for a while) */ 123b7db1904Seric (void) close(port); 1242554d49fSeric 1252554d49fSeric /* pick up old zombies; implement load limiting */ 1262554d49fSeric numconnections++; 1272554d49fSeric while (wait3(&status, numconnections < MAXCONNS ? WNOHANG : 0, 0) > 0) 1282554d49fSeric numconnections--; 129a8268164Seric } 1307fa39d90Seric } 131d0a9e852Seric /* 132d0a9e852Seric ** GETCONNECTION -- make a connection with the outside world 133d0a9e852Seric ** 134d0a9e852Seric ** Parameters: 135d0a9e852Seric ** none. 136d0a9e852Seric ** 137d0a9e852Seric ** Returns: 138d0a9e852Seric ** The port for mail traffic. 139d0a9e852Seric ** 140d0a9e852Seric ** Side Effects: 141d0a9e852Seric ** Waits for a connection. 142d0a9e852Seric */ 143d0a9e852Seric 1442554d49fSeric #define IPPORT_PLAYPORT 3055 /* random number */ 1452554d49fSeric 146038c4785Seric struct sockaddr_in SendmailAddress = { AF_INET, IPPORT_SMTP }; 147d0a9e852Seric 148d0a9e852Seric getconnection() 149d0a9e852Seric { 150d0a9e852Seric register int s; 151d0a9e852Seric struct sockaddr otherend; 152d0a9e852Seric 153d0a9e852Seric /* 154d0a9e852Seric ** Set up the address for the mailer. 155d0a9e852Seric */ 156d0a9e852Seric 15719cf7d27Seric SendmailAddress.sin_addr.s_addr = 0; 15848ff0a9dSeric SendmailAddress.sin_port = IPPORT_SMTP; 1592554d49fSeric # ifdef DEBUG 160*61e4310fSeric if (tTd(15, 15)) 1612554d49fSeric SendmailAddress.sin_port = IPPORT_PLAYPORT; 1622554d49fSeric # endif DEBUG 1632554d49fSeric SendmailAddress.sin_port = htons(SendmailAddress.sin_port); 164d0a9e852Seric 165d0a9e852Seric /* 166d0a9e852Seric ** Try to actually open the connection. 167d0a9e852Seric */ 168d0a9e852Seric 169d0a9e852Seric # ifdef DEBUG 170*61e4310fSeric if (tTd(15, 1)) 17119cf7d27Seric printf("getconnection\n"); 172d0a9e852Seric # endif DEBUG 173d0a9e852Seric 17447b12ae1Seric for (;;) 17547b12ae1Seric { 17647b12ae1Seric /* get a socket for the SMTP connection */ 177d0a9e852Seric s = socket(SOCK_STREAM, 0, &SendmailAddress, SO_ACCEPTCONN); 1782554d49fSeric if (s < 0) 1792554d49fSeric { 18047b12ae1Seric /* probably another daemon already */ 18147b12ae1Seric syserr("getconnection: can't create socket"); 18247b12ae1Seric break; 1832554d49fSeric } 184d0a9e852Seric 185d0a9e852Seric # ifdef DEBUG 186*61e4310fSeric if (tTd(15, 1)) 187d0a9e852Seric printf("getconnection: %d\n", s); 188d0a9e852Seric # endif DEBUG 18947b12ae1Seric 19047b12ae1Seric /* wait for a connection */ 19147b12ae1Seric if (accept(s, &otherend) >= 0) 19247b12ae1Seric break; 19347b12ae1Seric 19447b12ae1Seric /* probably innocuous -- retry */ 195fd8b367dSeric if (errno == ETIMEDOUT) 196fd8b367dSeric continue; 19747b12ae1Seric syserr("getconnection: accept"); 198210215eaSeric (void) close(s); 19947b12ae1Seric sleep(20); 2002554d49fSeric } 201d0a9e852Seric 202d0a9e852Seric return (s); 203d0a9e852Seric } 2047aa493c5Seric /* 2057aa493c5Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 2067aa493c5Seric ** 2077aa493c5Seric ** Parameters: 2087aa493c5Seric ** host -- the name of the host. 20948ff0a9dSeric ** port -- the port number to connect to. 2107aa493c5Seric ** outfile -- a pointer to a place to put the outfile 2117aa493c5Seric ** descriptor. 2127aa493c5Seric ** infile -- ditto for infile. 2137aa493c5Seric ** 2147aa493c5Seric ** Returns: 2157aa493c5Seric ** An exit code telling whether the connection could be 2167aa493c5Seric ** made and if not why not. 2177aa493c5Seric ** 2187aa493c5Seric ** Side Effects: 2197aa493c5Seric ** none. 2207aa493c5Seric */ 2217aa493c5Seric 22248ff0a9dSeric makeconnection(host, port, outfile, infile) 2237aa493c5Seric char *host; 224210215eaSeric u_short port; 2257aa493c5Seric FILE **outfile; 2267aa493c5Seric FILE **infile; 2277aa493c5Seric { 2287aa493c5Seric register int s; 2297aa493c5Seric 2307aa493c5Seric /* 2317aa493c5Seric ** Set up the address for the mailer. 2327aa493c5Seric */ 2337aa493c5Seric 2347aa493c5Seric if ((SendmailAddress.sin_addr.s_addr = rhost(&host)) == -1) 2357aa493c5Seric return (EX_NOHOST); 23648ff0a9dSeric if (port == 0) 23748ff0a9dSeric port = IPPORT_SMTP; 2382554d49fSeric SendmailAddress.sin_port = htons(port); 2397aa493c5Seric 2407aa493c5Seric /* 2417aa493c5Seric ** Try to actually open the connection. 2427aa493c5Seric */ 2437aa493c5Seric 2447aa493c5Seric # ifdef DEBUG 245*61e4310fSeric if (tTd(16, 1)) 2467aa493c5Seric printf("makeconnection (%s)\n", host); 2477aa493c5Seric # endif DEBUG 2487aa493c5Seric 249b7db1904Seric s = socket(SOCK_STREAM, 0, (struct sockaddr_in *) 0, 0); 2507aa493c5Seric if (s < 0) 2517aa493c5Seric { 2527aa493c5Seric syserr("makeconnection: no socket"); 2537aa493c5Seric goto failure; 2547aa493c5Seric } 2557aa493c5Seric 2567aa493c5Seric # ifdef DEBUG 257*61e4310fSeric if (tTd(16, 1)) 2587aa493c5Seric printf("makeconnection: %d\n", s); 2597aa493c5Seric # endif DEBUG 260*61e4310fSeric (void) fflush(Xscript); /* for debugging */ 2617aa493c5Seric if (connect(s, &SendmailAddress) < 0) 2627aa493c5Seric { 2637aa493c5Seric /* failure, decide if temporary or not */ 2647aa493c5Seric failure: 2657aa493c5Seric switch (errno) 2667aa493c5Seric { 2677aa493c5Seric case EISCONN: 2687aa493c5Seric case ETIMEDOUT: 269292668b9Seric case EINPROGRESS: 270292668b9Seric case EALREADY: 271292668b9Seric case EADDRINUSE: 272292668b9Seric case ENETDOWN: 273292668b9Seric case ENETRESET: 274292668b9Seric case ENOBUFS: 275a1645df8Seric case ECONNREFUSED: 2767aa493c5Seric /* there are others, I'm sure..... */ 2777aa493c5Seric return (EX_TEMPFAIL); 2787aa493c5Seric 2797aa493c5Seric default: 2807aa493c5Seric return (EX_UNAVAILABLE); 2817aa493c5Seric } 2827aa493c5Seric } 2837aa493c5Seric 2847aa493c5Seric /* connection ok, put it into canonical form */ 2857aa493c5Seric *outfile = fdopen(s, "w"); 2867aa493c5Seric *infile = fdopen(s, "r"); 2877aa493c5Seric 2887aa493c5Seric return (0); 2897aa493c5Seric } 290d0a9e852Seric 291d0a9e852Seric #endif DAEMON 292