16039Seric # include <errno.h> 24535Seric # include "sendmail.h" 34535Seric 45978Seric #ifndef DAEMON 5*7286Seric SCCSID(@(#)daemon.c 3.16 06/26/82 (w/o daemon mode)); 65978Seric #else 74535Seric 85978Seric # include <sys/socket.h> 95978Seric # include <net/in.h> 107117Seric # include <wait.h> 115978Seric 12*7286Seric SCCSID(@(#)daemon.c 3.16 06/26/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 337117Seric # define MAXCONNS 4 /* maximum simultaneous sendmails */ 347117Seric 354535Seric getrequests() 364535Seric { 377117Seric union wait status; 387117Seric int numconnections = 0; 397117Seric 404631Seric for (;;) 414631Seric { 424636Seric register int pid; 435978Seric register int port; 444631Seric 454636Seric /* 464636Seric ** Wait for a connection. 474636Seric */ 484631Seric 495978Seric while ((port = getconnection()) < 0) 505978Seric { 515978Seric syserr("getrequests: getconnection failed"); 525978Seric sleep(30); 535978Seric } 544631Seric 555978Seric /* 565978Seric ** Create a subprocess to process the mail. 575978Seric */ 585978Seric 595978Seric # ifdef DEBUG 605978Seric if (Debug > 1) 615978Seric printf("getrequests: forking (port = %d)\n", port); 625978Seric # endif DEBUG 635978Seric 644636Seric pid = fork(); 654636Seric if (pid < 0) 664631Seric { 674636Seric syserr("daemon: cannot fork"); 684636Seric sleep(10); 697009Seric (void) close(port); 704636Seric continue; 714631Seric } 724631Seric 734636Seric if (pid == 0) 744631Seric { 754636Seric /* 764636Seric ** CHILD -- return to caller. 774636Seric ** Verify calling user id if possible here. 784636Seric */ 794631Seric 805978Seric InChannel = fdopen(port, "r"); 815978Seric OutChannel = fdopen(port, "w"); 824636Seric initsys(); 835978Seric # ifdef DEBUG 845978Seric if (Debug > 1) 855978Seric printf("getreq: returning\n"); 865978Seric # endif DEBUG 874636Seric return; 884631Seric } 894631Seric 904636Seric /* 914636Seric ** PARENT -- wait for child to terminate. 924636Seric ** Perhaps we should allow concurrent processing? 934636Seric */ 944631Seric 955978Seric # ifdef DEBUG 965978Seric if (Debug > 1) 975978Seric { 985978Seric sleep(2); 995978Seric printf("getreq: parent waiting\n"); 1005978Seric } 1015978Seric # endif DEBUG 1025978Seric 1037117Seric /* close the port so that others will hang (for a while) */ 1047009Seric (void) close(port); 1057117Seric 1067117Seric /* pick up old zombies; implement load limiting */ 1077117Seric numconnections++; 1087117Seric while (wait3(&status, numconnections < MAXCONNS ? WNOHANG : 0, 0) > 0) 1097117Seric numconnections--; 1104631Seric } 1114631Seric } 1125978Seric /* 1135978Seric ** GETCONNECTION -- make a connection with the outside world 1145978Seric ** 1155978Seric ** Parameters: 1165978Seric ** none. 1175978Seric ** 1185978Seric ** Returns: 1195978Seric ** The port for mail traffic. 1205978Seric ** 1215978Seric ** Side Effects: 1225978Seric ** Waits for a connection. 1235978Seric */ 1245978Seric 1257117Seric #define IPPORT_PLAYPORT 3055 /* random number */ 1267117Seric 1275979Seric struct sockaddr_in SendmailAddress = { AF_INET, IPPORT_SMTP }; 1285978Seric 1295978Seric getconnection() 1305978Seric { 1315978Seric register int s; 1325978Seric struct sockaddr otherend; 1335978Seric 1345978Seric /* 1355978Seric ** Set up the address for the mailer. 1365978Seric */ 1375978Seric 1386058Seric SendmailAddress.sin_addr.s_addr = 0; 1396633Seric SendmailAddress.sin_port = IPPORT_SMTP; 1407117Seric # ifdef DEBUG 1417117Seric if (Debug > 0) 1427117Seric SendmailAddress.sin_port = IPPORT_PLAYPORT; 1437117Seric # endif DEBUG 1447117Seric SendmailAddress.sin_port = htons(SendmailAddress.sin_port); 1455978Seric 1465978Seric /* 1475978Seric ** Try to actually open the connection. 1485978Seric */ 1495978Seric 1505978Seric # ifdef DEBUG 1515978Seric if (Debug) 1526058Seric printf("getconnection\n"); 1535978Seric # endif DEBUG 1545978Seric 1555978Seric s = socket(SOCK_STREAM, 0, &SendmailAddress, SO_ACCEPTCONN); 1567117Seric if (s < 0) 1577117Seric { 1587117Seric sleep(10); 1597117Seric return (s); 1607117Seric } 1615978Seric 1625978Seric # ifdef DEBUG 1635978Seric if (Debug) 1645978Seric printf("getconnection: %d\n", s); 1655978Seric # endif DEBUG 1667117Seric if (accept(s, &otherend) < 0) 1677117Seric { 1687117Seric syserr("accept"); 169*7286Seric (void) close(s); 1707117Seric return (-1); 1717117Seric } 1725978Seric 1735978Seric return (s); 1745978Seric } 1756039Seric /* 1766039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 1776039Seric ** 1786039Seric ** Parameters: 1796039Seric ** host -- the name of the host. 1806633Seric ** port -- the port number to connect to. 1816039Seric ** outfile -- a pointer to a place to put the outfile 1826039Seric ** descriptor. 1836039Seric ** infile -- ditto for infile. 1846039Seric ** 1856039Seric ** Returns: 1866039Seric ** An exit code telling whether the connection could be 1876039Seric ** made and if not why not. 1886039Seric ** 1896039Seric ** Side Effects: 1906039Seric ** none. 1916039Seric */ 1925978Seric 1936633Seric makeconnection(host, port, outfile, infile) 1946039Seric char *host; 195*7286Seric u_short port; 1966039Seric FILE **outfile; 1976039Seric FILE **infile; 1986039Seric { 1996039Seric register int s; 2006039Seric 2016039Seric /* 2026039Seric ** Set up the address for the mailer. 2036039Seric */ 2046039Seric 2056039Seric if ((SendmailAddress.sin_addr.s_addr = rhost(&host)) == -1) 2066039Seric return (EX_NOHOST); 2076633Seric if (port == 0) 2086633Seric port = IPPORT_SMTP; 2097117Seric SendmailAddress.sin_port = htons(port); 2106039Seric 2116039Seric /* 2126039Seric ** Try to actually open the connection. 2136039Seric */ 2146039Seric 2156039Seric # ifdef DEBUG 2166039Seric if (Debug) 2176039Seric printf("makeconnection (%s)\n", host); 2186039Seric # endif DEBUG 2196039Seric 2207009Seric s = socket(SOCK_STREAM, 0, (struct sockaddr_in *) 0, 0); 2216039Seric if (s < 0) 2226039Seric { 2236039Seric syserr("makeconnection: no socket"); 2246039Seric goto failure; 2256039Seric } 2266039Seric 2276039Seric # ifdef DEBUG 2286039Seric if (Debug) 2296039Seric printf("makeconnection: %d\n", s); 2306039Seric # endif DEBUG 2316039Seric if (connect(s, &SendmailAddress) < 0) 2326039Seric { 2336039Seric /* failure, decide if temporary or not */ 2346039Seric failure: 2356039Seric switch (errno) 2366039Seric { 2376039Seric case EISCONN: 2386039Seric case ETIMEDOUT: 2396897Seric case EINPROGRESS: 2406897Seric case EALREADY: 2416897Seric case EADDRINUSE: 2426897Seric case ENETDOWN: 2436897Seric case ENETRESET: 2446897Seric case ENOBUFS: 2457204Seric case ECONNREFUSED: 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