17aa493c5Seric # include <errno.h> 27fa39d90Seric # include "sendmail.h" 37fa39d90Seric 4d0a9e852Seric #ifndef DAEMON 5*210215eaSeric SCCSID(@(#)daemon.c 3.16 06/26/82 (w/o daemon mode)); 6d0a9e852Seric #else 7d0a9e852Seric 8d0a9e852Seric # include <sys/socket.h> 9d0a9e852Seric # include <net/in.h> 102554d49fSeric # include <wait.h> 11d0a9e852Seric 12*210215eaSeric SCCSID(@(#)daemon.c 3.16 06/26/82 (with daemon mode)); 137fa39d90Seric 147fa39d90Seric /* 157fa39d90Seric ** DAEMON.C -- routines to use when running as a daemon. 167fa39d90Seric */ 177fa39d90Seric /* 187fa39d90Seric ** GETREQUESTS -- open mail IPC port and get requests. 197fa39d90Seric ** 207fa39d90Seric ** Parameters: 217fa39d90Seric ** none. 227fa39d90Seric ** 237fa39d90Seric ** Returns: 247fa39d90Seric ** none. 257fa39d90Seric ** 267fa39d90Seric ** Side Effects: 277fa39d90Seric ** Waits until some interesting activity occurs. When 287fa39d90Seric ** it does, a child is created to process it, and the 297fa39d90Seric ** parent waits for completion. Return from this 307fa39d90Seric ** routine is always in the child. 317fa39d90Seric */ 327fa39d90Seric 332554d49fSeric # define MAXCONNS 4 /* maximum simultaneous sendmails */ 342554d49fSeric 357fa39d90Seric getrequests() 367fa39d90Seric { 372554d49fSeric union wait status; 382554d49fSeric int numconnections = 0; 392554d49fSeric 40eb889047Seric for (;;) 41eb889047Seric { 42a8268164Seric register int pid; 43d0a9e852Seric register int port; 44eb889047Seric 45a8268164Seric /* 46a8268164Seric ** Wait for a connection. 47eb889047Seric */ 48eb889047Seric 49d0a9e852Seric while ((port = getconnection()) < 0) 50d0a9e852Seric { 51d0a9e852Seric syserr("getrequests: getconnection failed"); 52d0a9e852Seric sleep(30); 53d0a9e852Seric } 54d0a9e852Seric 55d0a9e852Seric /* 56d0a9e852Seric ** Create a subprocess to process the mail. 57d0a9e852Seric */ 58d0a9e852Seric 59d0a9e852Seric # ifdef DEBUG 60d0a9e852Seric if (Debug > 1) 61d0a9e852Seric printf("getrequests: forking (port = %d)\n", port); 62d0a9e852Seric # endif DEBUG 63eb889047Seric 64a8268164Seric pid = fork(); 65a8268164Seric if (pid < 0) 66a8268164Seric { 67a8268164Seric syserr("daemon: cannot fork"); 68a8268164Seric sleep(10); 69b7db1904Seric (void) close(port); 70a8268164Seric continue; 71a8268164Seric } 72a8268164Seric 73a8268164Seric if (pid == 0) 74a8268164Seric { 75a8268164Seric /* 76a8268164Seric ** CHILD -- return to caller. 77a8268164Seric ** Verify calling user id if possible here. 78a8268164Seric */ 79a8268164Seric 80d0a9e852Seric InChannel = fdopen(port, "r"); 81d0a9e852Seric OutChannel = fdopen(port, "w"); 82a8268164Seric initsys(); 83d0a9e852Seric # ifdef DEBUG 84d0a9e852Seric if (Debug > 1) 85d0a9e852Seric printf("getreq: returning\n"); 86d0a9e852Seric # endif DEBUG 87a8268164Seric return; 88a8268164Seric } 89a8268164Seric 90a8268164Seric /* 91a8268164Seric ** PARENT -- wait for child to terminate. 92a8268164Seric ** Perhaps we should allow concurrent processing? 93a8268164Seric */ 94a8268164Seric 95d0a9e852Seric # ifdef DEBUG 96d0a9e852Seric if (Debug > 1) 97d0a9e852Seric { 98d0a9e852Seric sleep(2); 99d0a9e852Seric printf("getreq: parent waiting\n"); 100d0a9e852Seric } 101d0a9e852Seric # endif DEBUG 102d0a9e852Seric 1032554d49fSeric /* close the port so that others will hang (for a while) */ 104b7db1904Seric (void) close(port); 1052554d49fSeric 1062554d49fSeric /* pick up old zombies; implement load limiting */ 1072554d49fSeric numconnections++; 1082554d49fSeric while (wait3(&status, numconnections < MAXCONNS ? WNOHANG : 0, 0) > 0) 1092554d49fSeric numconnections--; 110a8268164Seric } 1117fa39d90Seric } 112d0a9e852Seric /* 113d0a9e852Seric ** GETCONNECTION -- make a connection with the outside world 114d0a9e852Seric ** 115d0a9e852Seric ** Parameters: 116d0a9e852Seric ** none. 117d0a9e852Seric ** 118d0a9e852Seric ** Returns: 119d0a9e852Seric ** The port for mail traffic. 120d0a9e852Seric ** 121d0a9e852Seric ** Side Effects: 122d0a9e852Seric ** Waits for a connection. 123d0a9e852Seric */ 124d0a9e852Seric 1252554d49fSeric #define IPPORT_PLAYPORT 3055 /* random number */ 1262554d49fSeric 127038c4785Seric struct sockaddr_in SendmailAddress = { AF_INET, IPPORT_SMTP }; 128d0a9e852Seric 129d0a9e852Seric getconnection() 130d0a9e852Seric { 131d0a9e852Seric register int s; 132d0a9e852Seric struct sockaddr otherend; 133d0a9e852Seric 134d0a9e852Seric /* 135d0a9e852Seric ** Set up the address for the mailer. 136d0a9e852Seric */ 137d0a9e852Seric 13819cf7d27Seric SendmailAddress.sin_addr.s_addr = 0; 13948ff0a9dSeric SendmailAddress.sin_port = IPPORT_SMTP; 1402554d49fSeric # ifdef DEBUG 1412554d49fSeric if (Debug > 0) 1422554d49fSeric SendmailAddress.sin_port = IPPORT_PLAYPORT; 1432554d49fSeric # endif DEBUG 1442554d49fSeric SendmailAddress.sin_port = htons(SendmailAddress.sin_port); 145d0a9e852Seric 146d0a9e852Seric /* 147d0a9e852Seric ** Try to actually open the connection. 148d0a9e852Seric */ 149d0a9e852Seric 150d0a9e852Seric # ifdef DEBUG 151d0a9e852Seric if (Debug) 15219cf7d27Seric printf("getconnection\n"); 153d0a9e852Seric # endif DEBUG 154d0a9e852Seric 155d0a9e852Seric s = socket(SOCK_STREAM, 0, &SendmailAddress, SO_ACCEPTCONN); 1562554d49fSeric if (s < 0) 1572554d49fSeric { 1582554d49fSeric sleep(10); 1592554d49fSeric return (s); 1602554d49fSeric } 161d0a9e852Seric 162d0a9e852Seric # ifdef DEBUG 163d0a9e852Seric if (Debug) 164d0a9e852Seric printf("getconnection: %d\n", s); 165d0a9e852Seric # endif DEBUG 1662554d49fSeric if (accept(s, &otherend) < 0) 1672554d49fSeric { 1682554d49fSeric syserr("accept"); 169*210215eaSeric (void) close(s); 1702554d49fSeric return (-1); 1712554d49fSeric } 172d0a9e852Seric 173d0a9e852Seric return (s); 174d0a9e852Seric } 1757aa493c5Seric /* 1767aa493c5Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 1777aa493c5Seric ** 1787aa493c5Seric ** Parameters: 1797aa493c5Seric ** host -- the name of the host. 18048ff0a9dSeric ** port -- the port number to connect to. 1817aa493c5Seric ** outfile -- a pointer to a place to put the outfile 1827aa493c5Seric ** descriptor. 1837aa493c5Seric ** infile -- ditto for infile. 1847aa493c5Seric ** 1857aa493c5Seric ** Returns: 1867aa493c5Seric ** An exit code telling whether the connection could be 1877aa493c5Seric ** made and if not why not. 1887aa493c5Seric ** 1897aa493c5Seric ** Side Effects: 1907aa493c5Seric ** none. 1917aa493c5Seric */ 1927aa493c5Seric 19348ff0a9dSeric makeconnection(host, port, outfile, infile) 1947aa493c5Seric char *host; 195*210215eaSeric u_short port; 1967aa493c5Seric FILE **outfile; 1977aa493c5Seric FILE **infile; 1987aa493c5Seric { 1997aa493c5Seric register int s; 2007aa493c5Seric 2017aa493c5Seric /* 2027aa493c5Seric ** Set up the address for the mailer. 2037aa493c5Seric */ 2047aa493c5Seric 2057aa493c5Seric if ((SendmailAddress.sin_addr.s_addr = rhost(&host)) == -1) 2067aa493c5Seric return (EX_NOHOST); 20748ff0a9dSeric if (port == 0) 20848ff0a9dSeric port = IPPORT_SMTP; 2092554d49fSeric SendmailAddress.sin_port = htons(port); 2107aa493c5Seric 2117aa493c5Seric /* 2127aa493c5Seric ** Try to actually open the connection. 2137aa493c5Seric */ 2147aa493c5Seric 2157aa493c5Seric # ifdef DEBUG 2167aa493c5Seric if (Debug) 2177aa493c5Seric printf("makeconnection (%s)\n", host); 2187aa493c5Seric # endif DEBUG 2197aa493c5Seric 220b7db1904Seric s = socket(SOCK_STREAM, 0, (struct sockaddr_in *) 0, 0); 2217aa493c5Seric if (s < 0) 2227aa493c5Seric { 2237aa493c5Seric syserr("makeconnection: no socket"); 2247aa493c5Seric goto failure; 2257aa493c5Seric } 2267aa493c5Seric 2277aa493c5Seric # ifdef DEBUG 2287aa493c5Seric if (Debug) 2297aa493c5Seric printf("makeconnection: %d\n", s); 2307aa493c5Seric # endif DEBUG 2317aa493c5Seric if (connect(s, &SendmailAddress) < 0) 2327aa493c5Seric { 2337aa493c5Seric /* failure, decide if temporary or not */ 2347aa493c5Seric failure: 2357aa493c5Seric switch (errno) 2367aa493c5Seric { 2377aa493c5Seric case EISCONN: 2387aa493c5Seric case ETIMEDOUT: 239292668b9Seric case EINPROGRESS: 240292668b9Seric case EALREADY: 241292668b9Seric case EADDRINUSE: 242292668b9Seric case ENETDOWN: 243292668b9Seric case ENETRESET: 244292668b9Seric case ENOBUFS: 245a1645df8Seric case ECONNREFUSED: 2467aa493c5Seric /* there are others, I'm sure..... */ 2477aa493c5Seric return (EX_TEMPFAIL); 2487aa493c5Seric 2497aa493c5Seric default: 2507aa493c5Seric return (EX_UNAVAILABLE); 2517aa493c5Seric } 2527aa493c5Seric } 2537aa493c5Seric 2547aa493c5Seric /* connection ok, put it into canonical form */ 2557aa493c5Seric *outfile = fdopen(s, "w"); 2567aa493c5Seric *infile = fdopen(s, "r"); 2577aa493c5Seric 2587aa493c5Seric return (0); 2597aa493c5Seric } 260d0a9e852Seric 261d0a9e852Seric #endif DAEMON 262