17aa493c5Seric # include <errno.h> 27fa39d90Seric # include "sendmail.h" 37fa39d90Seric 4d0a9e852Seric #ifndef DAEMON 5*47b12ae1Seric SCCSID(@(#)daemon.c 3.20 07/27/82 (w/o daemon mode)); 6d0a9e852Seric #else 7d0a9e852Seric 8d0a9e852Seric # include <sys/socket.h> 9d0a9e852Seric # include <net/in.h> 102554d49fSeric # include <wait.h> 11d0a9e852Seric 12*47b12ae1Seric SCCSID(@(#)daemon.c 3.20 07/27/82 (with daemon mode)); 137fa39d90Seric 147fa39d90Seric /* 157fa39d90Seric ** DAEMON.C -- routines to use when running as a daemon. 16*47b12ae1Seric ** 17*47b12ae1Seric ** This entire file is highly dependent on the 4.2 BSD 18*47b12ae1Seric ** interprocess communication primitives. No attempt has 19*47b12ae1Seric ** been made to make this file portable to Version 7, 20*47b12ae1Seric ** Version 6, MPX files, etc. If you should try such a 21*47b12ae1Seric ** thing yourself, I recommend chucking the entire file 22*47b12ae1Seric ** and starting from scratch. Basic semantics are: 23*47b12ae1Seric ** 24*47b12ae1Seric ** getrequests() 25*47b12ae1Seric ** Opens a port and initiates a connection. 26*47b12ae1Seric ** Returns in a child. Must set InChannel and 27*47b12ae1Seric ** OutChannel appropriately. 28*47b12ae1Seric ** makeconnection(host, port, outfile, infile) 29*47b12ae1Seric ** Make a connection to the named host on the given 30*47b12ae1Seric ** port. Set *outfile and *infile to the files 31*47b12ae1Seric ** appropriate for communication. Returns zero on 32*47b12ae1Seric ** success, else an exit status describing the 33*47b12ae1Seric ** error. 34*47b12ae1Seric ** 35*47b12ae1Seric ** 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"); 72*47b12ae1Seric finis(); 73d0a9e852Seric } 74d0a9e852Seric 75d0a9e852Seric /* 76d0a9e852Seric ** Create a subprocess to process the mail. 77d0a9e852Seric */ 78d0a9e852Seric 79d0a9e852Seric # ifdef DEBUG 80d0a9e852Seric if (Debug > 1) 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 103d0a9e852Seric if (Debug > 1) 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 115d0a9e852Seric if (Debug > 1) 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 1602554d49fSeric if (Debug > 0) 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 170d0a9e852Seric if (Debug) 17119cf7d27Seric printf("getconnection\n"); 172d0a9e852Seric # endif DEBUG 173d0a9e852Seric 174*47b12ae1Seric for (;;) 175*47b12ae1Seric { 176*47b12ae1Seric /* get a socket for the SMTP connection */ 177d0a9e852Seric s = socket(SOCK_STREAM, 0, &SendmailAddress, SO_ACCEPTCONN); 1782554d49fSeric if (s < 0) 1792554d49fSeric { 180*47b12ae1Seric /* probably another daemon already */ 181*47b12ae1Seric syserr("getconnection: can't create socket"); 182*47b12ae1Seric break; 1832554d49fSeric } 184d0a9e852Seric 185d0a9e852Seric # ifdef DEBUG 186d0a9e852Seric if (Debug) 187d0a9e852Seric printf("getconnection: %d\n", s); 188d0a9e852Seric # endif DEBUG 189*47b12ae1Seric 190*47b12ae1Seric /* wait for a connection */ 191*47b12ae1Seric if (accept(s, &otherend) >= 0) 192*47b12ae1Seric break; 193*47b12ae1Seric 194*47b12ae1Seric /* probably innocuous -- retry */ 195*47b12ae1Seric syserr("getconnection: accept"); 196210215eaSeric (void) close(s); 197*47b12ae1Seric sleep(20); 1982554d49fSeric } 199d0a9e852Seric 200d0a9e852Seric return (s); 201d0a9e852Seric } 2027aa493c5Seric /* 2037aa493c5Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 2047aa493c5Seric ** 2057aa493c5Seric ** Parameters: 2067aa493c5Seric ** host -- the name of the host. 20748ff0a9dSeric ** port -- the port number to connect to. 2087aa493c5Seric ** outfile -- a pointer to a place to put the outfile 2097aa493c5Seric ** descriptor. 2107aa493c5Seric ** infile -- ditto for infile. 2117aa493c5Seric ** 2127aa493c5Seric ** Returns: 2137aa493c5Seric ** An exit code telling whether the connection could be 2147aa493c5Seric ** made and if not why not. 2157aa493c5Seric ** 2167aa493c5Seric ** Side Effects: 2177aa493c5Seric ** none. 2187aa493c5Seric */ 2197aa493c5Seric 22048ff0a9dSeric makeconnection(host, port, outfile, infile) 2217aa493c5Seric char *host; 222210215eaSeric u_short port; 2237aa493c5Seric FILE **outfile; 2247aa493c5Seric FILE **infile; 2257aa493c5Seric { 2267aa493c5Seric register int s; 2277aa493c5Seric 2287aa493c5Seric /* 2297aa493c5Seric ** Set up the address for the mailer. 2307aa493c5Seric */ 2317aa493c5Seric 2327aa493c5Seric if ((SendmailAddress.sin_addr.s_addr = rhost(&host)) == -1) 2337aa493c5Seric return (EX_NOHOST); 23448ff0a9dSeric if (port == 0) 23548ff0a9dSeric port = IPPORT_SMTP; 2362554d49fSeric SendmailAddress.sin_port = htons(port); 2377aa493c5Seric 2387aa493c5Seric /* 2397aa493c5Seric ** Try to actually open the connection. 2407aa493c5Seric */ 2417aa493c5Seric 2427aa493c5Seric # ifdef DEBUG 2437aa493c5Seric if (Debug) 2447aa493c5Seric printf("makeconnection (%s)\n", host); 2457aa493c5Seric # endif DEBUG 2467aa493c5Seric 247b7db1904Seric s = socket(SOCK_STREAM, 0, (struct sockaddr_in *) 0, 0); 2487aa493c5Seric if (s < 0) 2497aa493c5Seric { 2507aa493c5Seric syserr("makeconnection: no socket"); 2517aa493c5Seric goto failure; 2527aa493c5Seric } 2537aa493c5Seric 2547aa493c5Seric # ifdef DEBUG 2557aa493c5Seric if (Debug) 2567aa493c5Seric printf("makeconnection: %d\n", s); 2577aa493c5Seric # endif DEBUG 258e0551291Seric fflush(Xscript); /* for debugging */ 2597aa493c5Seric if (connect(s, &SendmailAddress) < 0) 2607aa493c5Seric { 2617aa493c5Seric /* failure, decide if temporary or not */ 2627aa493c5Seric failure: 2637aa493c5Seric switch (errno) 2647aa493c5Seric { 2657aa493c5Seric case EISCONN: 2667aa493c5Seric case ETIMEDOUT: 267292668b9Seric case EINPROGRESS: 268292668b9Seric case EALREADY: 269292668b9Seric case EADDRINUSE: 270292668b9Seric case ENETDOWN: 271292668b9Seric case ENETRESET: 272292668b9Seric case ENOBUFS: 273a1645df8Seric case ECONNREFUSED: 2747aa493c5Seric /* there are others, I'm sure..... */ 2757aa493c5Seric return (EX_TEMPFAIL); 2767aa493c5Seric 2777aa493c5Seric default: 2787aa493c5Seric return (EX_UNAVAILABLE); 2797aa493c5Seric } 2807aa493c5Seric } 2817aa493c5Seric 2827aa493c5Seric /* connection ok, put it into canonical form */ 2837aa493c5Seric *outfile = fdopen(s, "w"); 2847aa493c5Seric *infile = fdopen(s, "r"); 2857aa493c5Seric 2867aa493c5Seric return (0); 2877aa493c5Seric } 288d0a9e852Seric 289d0a9e852Seric #endif DAEMON 290