16039Seric # include <errno.h> 24535Seric # include "sendmail.h" 34535Seric 45978Seric #ifndef DAEMON 5*7346Seric SCCSID(@(#)daemon.c 3.18 07/02/82 (w/o daemon mode)); 65978Seric #else 74535Seric 85978Seric # include <sys/socket.h> 95978Seric # include <net/in.h> 107117Seric # include <wait.h> 115978Seric 12*7346Seric SCCSID(@(#)daemon.c 3.18 07/02/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. 78*7346Seric ** Make sure we reset state from parent. 794636Seric */ 804631Seric 81*7346Seric FatalErrors = FALSE; 825978Seric InChannel = fdopen(port, "r"); 835978Seric OutChannel = fdopen(port, "w"); 847339Seric openxscrpt(); 854636Seric initsys(); 865978Seric # ifdef DEBUG 875978Seric if (Debug > 1) 885978Seric printf("getreq: returning\n"); 895978Seric # endif DEBUG 904636Seric return; 914631Seric } 924631Seric 934636Seric /* 944636Seric ** PARENT -- wait for child to terminate. 954636Seric ** Perhaps we should allow concurrent processing? 964636Seric */ 974631Seric 985978Seric # ifdef DEBUG 995978Seric if (Debug > 1) 1005978Seric { 1015978Seric sleep(2); 1025978Seric printf("getreq: parent waiting\n"); 1035978Seric } 1045978Seric # endif DEBUG 1055978Seric 1067117Seric /* close the port so that others will hang (for a while) */ 1077009Seric (void) close(port); 1087117Seric 1097117Seric /* pick up old zombies; implement load limiting */ 1107117Seric numconnections++; 1117117Seric while (wait3(&status, numconnections < MAXCONNS ? WNOHANG : 0, 0) > 0) 1127117Seric numconnections--; 1134631Seric } 1144631Seric } 1155978Seric /* 1165978Seric ** GETCONNECTION -- make a connection with the outside world 1175978Seric ** 1185978Seric ** Parameters: 1195978Seric ** none. 1205978Seric ** 1215978Seric ** Returns: 1225978Seric ** The port for mail traffic. 1235978Seric ** 1245978Seric ** Side Effects: 1255978Seric ** Waits for a connection. 1265978Seric */ 1275978Seric 1287117Seric #define IPPORT_PLAYPORT 3055 /* random number */ 1297117Seric 1305979Seric struct sockaddr_in SendmailAddress = { AF_INET, IPPORT_SMTP }; 1315978Seric 1325978Seric getconnection() 1335978Seric { 1345978Seric register int s; 1355978Seric struct sockaddr otherend; 1365978Seric 1375978Seric /* 1385978Seric ** Set up the address for the mailer. 1395978Seric */ 1405978Seric 1416058Seric SendmailAddress.sin_addr.s_addr = 0; 1426633Seric SendmailAddress.sin_port = IPPORT_SMTP; 1437117Seric # ifdef DEBUG 1447117Seric if (Debug > 0) 1457117Seric SendmailAddress.sin_port = IPPORT_PLAYPORT; 1467117Seric # endif DEBUG 1477117Seric SendmailAddress.sin_port = htons(SendmailAddress.sin_port); 1485978Seric 1495978Seric /* 1505978Seric ** Try to actually open the connection. 1515978Seric */ 1525978Seric 1535978Seric # ifdef DEBUG 1545978Seric if (Debug) 1556058Seric printf("getconnection\n"); 1565978Seric # endif DEBUG 1575978Seric 1585978Seric s = socket(SOCK_STREAM, 0, &SendmailAddress, SO_ACCEPTCONN); 1597117Seric if (s < 0) 1607117Seric { 1617117Seric sleep(10); 1627117Seric return (s); 1637117Seric } 1645978Seric 1655978Seric # ifdef DEBUG 1665978Seric if (Debug) 1675978Seric printf("getconnection: %d\n", s); 1685978Seric # endif DEBUG 1697117Seric if (accept(s, &otherend) < 0) 1707117Seric { 1717117Seric syserr("accept"); 1727286Seric (void) close(s); 1737117Seric return (-1); 1747117Seric } 1755978Seric 1765978Seric return (s); 1775978Seric } 1786039Seric /* 1796039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 1806039Seric ** 1816039Seric ** Parameters: 1826039Seric ** host -- the name of the host. 1836633Seric ** port -- the port number to connect to. 1846039Seric ** outfile -- a pointer to a place to put the outfile 1856039Seric ** descriptor. 1866039Seric ** infile -- ditto for infile. 1876039Seric ** 1886039Seric ** Returns: 1896039Seric ** An exit code telling whether the connection could be 1906039Seric ** made and if not why not. 1916039Seric ** 1926039Seric ** Side Effects: 1936039Seric ** none. 1946039Seric */ 1955978Seric 1966633Seric makeconnection(host, port, outfile, infile) 1976039Seric char *host; 1987286Seric u_short port; 1996039Seric FILE **outfile; 2006039Seric FILE **infile; 2016039Seric { 2026039Seric register int s; 2036039Seric 2046039Seric /* 2056039Seric ** Set up the address for the mailer. 2066039Seric */ 2076039Seric 2086039Seric if ((SendmailAddress.sin_addr.s_addr = rhost(&host)) == -1) 2096039Seric return (EX_NOHOST); 2106633Seric if (port == 0) 2116633Seric port = IPPORT_SMTP; 2127117Seric SendmailAddress.sin_port = htons(port); 2136039Seric 2146039Seric /* 2156039Seric ** Try to actually open the connection. 2166039Seric */ 2176039Seric 2186039Seric # ifdef DEBUG 2196039Seric if (Debug) 2206039Seric printf("makeconnection (%s)\n", host); 2216039Seric # endif DEBUG 2226039Seric 2237009Seric s = socket(SOCK_STREAM, 0, (struct sockaddr_in *) 0, 0); 2246039Seric if (s < 0) 2256039Seric { 2266039Seric syserr("makeconnection: no socket"); 2276039Seric goto failure; 2286039Seric } 2296039Seric 2306039Seric # ifdef DEBUG 2316039Seric if (Debug) 2326039Seric printf("makeconnection: %d\n", s); 2336039Seric # endif DEBUG 2346039Seric if (connect(s, &SendmailAddress) < 0) 2356039Seric { 2366039Seric /* failure, decide if temporary or not */ 2376039Seric failure: 2386039Seric switch (errno) 2396039Seric { 2406039Seric case EISCONN: 2416039Seric case ETIMEDOUT: 2426897Seric case EINPROGRESS: 2436897Seric case EALREADY: 2446897Seric case EADDRINUSE: 2456897Seric case ENETDOWN: 2466897Seric case ENETRESET: 2476897Seric case ENOBUFS: 2487204Seric case ECONNREFUSED: 2496039Seric /* there are others, I'm sure..... */ 2506039Seric return (EX_TEMPFAIL); 2516039Seric 2526039Seric default: 2536039Seric return (EX_UNAVAILABLE); 2546039Seric } 2556039Seric } 2566039Seric 2576039Seric /* connection ok, put it into canonical form */ 2586039Seric *outfile = fdopen(s, "w"); 2596039Seric *infile = fdopen(s, "r"); 2606039Seric 2616039Seric return (0); 2626039Seric } 2636039Seric 2645978Seric #endif DAEMON 265