16039Seric # include <errno.h> 24535Seric # include "sendmail.h" 34535Seric 45978Seric #ifndef DAEMON 5*7117Seric SCCSID(@(#)daemon.c 3.14 06/07/82 (w/o daemon mode)); 65978Seric #else 74535Seric 85978Seric # include <sys/socket.h> 95978Seric # include <net/in.h> 10*7117Seric # include <wait.h> 115978Seric 12*7117Seric SCCSID(@(#)daemon.c 3.14 06/07/82 (with daemon mode)); 135978Seric 144535Seric /* 154535Seric ** DAEMON.C -- routines to use when running as a daemon. 164535Seric */ 174535Seric /* 184535Seric ** GETREQUESTS -- open mail IPC port and get requests. 194535Seric ** 204535Seric ** Parameters: 214535Seric ** none. 224535Seric ** 234535Seric ** Returns: 244535Seric ** none. 254535Seric ** 264535Seric ** Side Effects: 274535Seric ** Waits until some interesting activity occurs. When 284535Seric ** it does, a child is created to process it, and the 294535Seric ** parent waits for completion. Return from this 304535Seric ** routine is always in the child. 314535Seric */ 324535Seric 33*7117Seric # define MAXCONNS 4 /* maximum simultaneous sendmails */ 34*7117Seric 354535Seric getrequests() 364535Seric { 37*7117Seric union wait status; 38*7117Seric int numconnections = 0; 39*7117Seric 404631Seric for (;;) 414631Seric { 424636Seric register int pid; 434636Seric auto int st; 445978Seric register int port; 454631Seric 464636Seric /* 474636Seric ** Wait for a connection. 484636Seric */ 494631Seric 505978Seric while ((port = getconnection()) < 0) 515978Seric { 525978Seric syserr("getrequests: getconnection failed"); 535978Seric sleep(30); 545978Seric } 554631Seric 565978Seric /* 575978Seric ** Create a subprocess to process the mail. 585978Seric */ 595978Seric 605978Seric # ifdef DEBUG 615978Seric if (Debug > 1) 625978Seric printf("getrequests: forking (port = %d)\n", port); 635978Seric # endif DEBUG 645978Seric 654636Seric pid = fork(); 664636Seric if (pid < 0) 674631Seric { 684636Seric syserr("daemon: cannot fork"); 694636Seric sleep(10); 707009Seric (void) close(port); 714636Seric continue; 724631Seric } 734631Seric 744636Seric if (pid == 0) 754631Seric { 764636Seric /* 774636Seric ** CHILD -- return to caller. 784636Seric ** Verify calling user id if possible here. 794636Seric */ 804631Seric 815978Seric InChannel = fdopen(port, "r"); 825978Seric OutChannel = fdopen(port, "w"); 834636Seric initsys(); 845978Seric # ifdef DEBUG 855978Seric if (Debug > 1) 865978Seric printf("getreq: returning\n"); 875978Seric # endif DEBUG 884636Seric return; 894631Seric } 904631Seric 914636Seric /* 924636Seric ** PARENT -- wait for child to terminate. 934636Seric ** Perhaps we should allow concurrent processing? 944636Seric */ 954631Seric 965978Seric # ifdef DEBUG 975978Seric if (Debug > 1) 985978Seric { 995978Seric sleep(2); 1005978Seric printf("getreq: parent waiting\n"); 1015978Seric } 1025978Seric # endif DEBUG 1035978Seric 104*7117Seric /* close the port so that others will hang (for a while) */ 1057009Seric (void) close(port); 106*7117Seric 107*7117Seric /* pick up old zombies; implement load limiting */ 108*7117Seric numconnections++; 109*7117Seric while (wait3(&status, numconnections < MAXCONNS ? WNOHANG : 0, 0) > 0) 110*7117Seric numconnections--; 1114631Seric } 1124631Seric } 1135978Seric /* 1145978Seric ** GETCONNECTION -- make a connection with the outside world 1155978Seric ** 1165978Seric ** Parameters: 1175978Seric ** none. 1185978Seric ** 1195978Seric ** Returns: 1205978Seric ** The port for mail traffic. 1215978Seric ** 1225978Seric ** Side Effects: 1235978Seric ** Waits for a connection. 1245978Seric */ 1255978Seric 126*7117Seric #define IPPORT_PLAYPORT 3055 /* random number */ 127*7117Seric 1285979Seric struct sockaddr_in SendmailAddress = { AF_INET, IPPORT_SMTP }; 1295978Seric 1305978Seric getconnection() 1315978Seric { 1325978Seric register int s; 1335978Seric struct sockaddr otherend; 1345978Seric 1355978Seric /* 1365978Seric ** Set up the address for the mailer. 1375978Seric */ 1385978Seric 1396058Seric SendmailAddress.sin_addr.s_addr = 0; 1406633Seric SendmailAddress.sin_port = IPPORT_SMTP; 141*7117Seric # ifdef DEBUG 142*7117Seric if (Debug > 0) 143*7117Seric SendmailAddress.sin_port = IPPORT_PLAYPORT; 144*7117Seric # endif DEBUG 145*7117Seric SendmailAddress.sin_port = htons(SendmailAddress.sin_port); 1465978Seric 1475978Seric /* 1485978Seric ** Try to actually open the connection. 1495978Seric */ 1505978Seric 1515978Seric # ifdef DEBUG 1525978Seric if (Debug) 1536058Seric printf("getconnection\n"); 1545978Seric # endif DEBUG 1555978Seric 1565978Seric s = socket(SOCK_STREAM, 0, &SendmailAddress, SO_ACCEPTCONN); 157*7117Seric if (s < 0) 158*7117Seric { 159*7117Seric sleep(10); 160*7117Seric return (s); 161*7117Seric } 1625978Seric 1635978Seric # ifdef DEBUG 1645978Seric if (Debug) 1655978Seric printf("getconnection: %d\n", s); 1665978Seric # endif DEBUG 167*7117Seric if (accept(s, &otherend) < 0) 168*7117Seric { 169*7117Seric syserr("accept"); 170*7117Seric close(s); 171*7117Seric return (-1); 172*7117Seric } 1735978Seric 1745978Seric return (s); 1755978Seric } 1766039Seric /* 1776039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 1786039Seric ** 1796039Seric ** Parameters: 1806039Seric ** host -- the name of the host. 1816633Seric ** port -- the port number to connect to. 1826039Seric ** outfile -- a pointer to a place to put the outfile 1836039Seric ** descriptor. 1846039Seric ** infile -- ditto for infile. 1856039Seric ** 1866039Seric ** Returns: 1876039Seric ** An exit code telling whether the connection could be 1886039Seric ** made and if not why not. 1896039Seric ** 1906039Seric ** Side Effects: 1916039Seric ** none. 1926039Seric */ 1935978Seric 1946633Seric makeconnection(host, port, outfile, infile) 1956039Seric char *host; 1966633Seric int port; 1976039Seric FILE **outfile; 1986039Seric FILE **infile; 1996039Seric { 2006039Seric register int s; 2016039Seric 2026039Seric /* 2036039Seric ** Set up the address for the mailer. 2046039Seric */ 2056039Seric 2066039Seric if ((SendmailAddress.sin_addr.s_addr = rhost(&host)) == -1) 2076039Seric return (EX_NOHOST); 2086633Seric if (port == 0) 2096633Seric port = IPPORT_SMTP; 210*7117Seric SendmailAddress.sin_port = htons(port); 2116039Seric 2126039Seric /* 2136039Seric ** Try to actually open the connection. 2146039Seric */ 2156039Seric 2166039Seric # ifdef DEBUG 2176039Seric if (Debug) 2186039Seric printf("makeconnection (%s)\n", host); 2196039Seric # endif DEBUG 2206039Seric 2217009Seric s = socket(SOCK_STREAM, 0, (struct sockaddr_in *) 0, 0); 2226039Seric if (s < 0) 2236039Seric { 2246039Seric syserr("makeconnection: no socket"); 2256039Seric goto failure; 2266039Seric } 2276039Seric 2286039Seric # ifdef DEBUG 2296039Seric if (Debug) 2306039Seric printf("makeconnection: %d\n", s); 2316039Seric # endif DEBUG 2326039Seric if (connect(s, &SendmailAddress) < 0) 2336039Seric { 2346039Seric /* failure, decide if temporary or not */ 2356039Seric failure: 2366039Seric switch (errno) 2376039Seric { 2386039Seric case EISCONN: 2396039Seric case ETIMEDOUT: 2406897Seric case EINPROGRESS: 2416897Seric case EALREADY: 2426897Seric case EADDRINUSE: 2436897Seric case ENETDOWN: 2446897Seric case ENETRESET: 2456897Seric case ENOBUFS: 2466039Seric /* there are others, I'm sure..... */ 2476039Seric return (EX_TEMPFAIL); 2486039Seric 2496039Seric default: 2506039Seric return (EX_UNAVAILABLE); 2516039Seric } 2526039Seric } 2536039Seric 2546039Seric /* connection ok, put it into canonical form */ 2556039Seric *outfile = fdopen(s, "w"); 2566039Seric *infile = fdopen(s, "r"); 2576039Seric 2586039Seric return (0); 2596039Seric } 2606039Seric 2615978Seric #endif DAEMON 262