16039Seric # include <errno.h> 24535Seric # include "sendmail.h" 34535Seric 45978Seric #ifndef DAEMON 5*7876Seric SCCSID(@(#)daemon.c 3.24 08/24/82 (w/o daemon mode)); 65978Seric #else 74535Seric 85978Seric # include <sys/socket.h> 95978Seric # include <net/in.h> 107117Seric # include <wait.h> 115978Seric 12*7876Seric SCCSID(@(#)daemon.c 3.24 08/24/82 (with daemon mode)); 135978Seric 144535Seric /* 154535Seric ** DAEMON.C -- routines to use when running as a daemon. 167556Seric ** 177556Seric ** This entire file is highly dependent on the 4.2 BSD 187556Seric ** interprocess communication primitives. No attempt has 197556Seric ** been made to make this file portable to Version 7, 207556Seric ** Version 6, MPX files, etc. If you should try such a 217556Seric ** thing yourself, I recommend chucking the entire file 227556Seric ** and starting from scratch. Basic semantics are: 237556Seric ** 247556Seric ** getrequests() 257556Seric ** Opens a port and initiates a connection. 267556Seric ** Returns in a child. Must set InChannel and 277556Seric ** OutChannel appropriately. 287556Seric ** makeconnection(host, port, outfile, infile) 297556Seric ** Make a connection to the named host on the given 307556Seric ** port. Set *outfile and *infile to the files 317556Seric ** appropriate for communication. Returns zero on 327556Seric ** success, else an exit status describing the 337556Seric ** error. 347556Seric ** 357556Seric ** The semantics of both of these should be clean. 364535Seric */ 374535Seric /* 384535Seric ** GETREQUESTS -- open mail IPC port and get requests. 394535Seric ** 404535Seric ** Parameters: 414535Seric ** none. 424535Seric ** 434535Seric ** Returns: 444535Seric ** none. 454535Seric ** 464535Seric ** Side Effects: 474535Seric ** Waits until some interesting activity occurs. When 484535Seric ** it does, a child is created to process it, and the 494535Seric ** parent waits for completion. Return from this 504535Seric ** routine is always in the child. 514535Seric */ 524535Seric 537117Seric # define MAXCONNS 4 /* maximum simultaneous sendmails */ 547117Seric 554535Seric getrequests() 564535Seric { 577117Seric union wait status; 587117Seric int numconnections = 0; 597117Seric 604631Seric for (;;) 614631Seric { 624636Seric register int pid; 635978Seric register int port; 644631Seric 654636Seric /* 664636Seric ** Wait for a connection. 674636Seric */ 684631Seric 695978Seric while ((port = getconnection()) < 0) 705978Seric { 715978Seric syserr("getrequests: getconnection failed"); 727556Seric finis(); 735978Seric } 744631Seric 755978Seric /* 765978Seric ** Create a subprocess to process the mail. 775978Seric */ 785978Seric 795978Seric # ifdef DEBUG 807677Seric if (tTd(15, 2)) 815978Seric printf("getrequests: forking (port = %d)\n", port); 825978Seric # endif DEBUG 835978Seric 844636Seric pid = fork(); 854636Seric if (pid < 0) 864631Seric { 874636Seric syserr("daemon: cannot fork"); 884636Seric sleep(10); 897009Seric (void) close(port); 904636Seric continue; 914631Seric } 924631Seric 934636Seric if (pid == 0) 944631Seric { 954636Seric /* 964636Seric ** CHILD -- return to caller. 974636Seric ** Verify calling user id if possible here. 984636Seric */ 994631Seric 1005978Seric InChannel = fdopen(port, "r"); 1015978Seric OutChannel = fdopen(port, "w"); 1025978Seric # ifdef DEBUG 1037677Seric if (tTd(15, 2)) 1045978Seric printf("getreq: returning\n"); 1055978Seric # endif DEBUG 106*7876Seric # ifdef LOG 107*7876Seric if (LogLevel > 11) 108*7876Seric syslog(LOG_DEBUG, "connected, pid=%d", getpid()); 109*7876Seric # endif LOG 1104636Seric return; 1114631Seric } 1124631Seric 1134636Seric /* 1144636Seric ** PARENT -- wait for child to terminate. 1154636Seric ** Perhaps we should allow concurrent processing? 1164636Seric */ 1174631Seric 1185978Seric # ifdef DEBUG 1197677Seric if (tTd(15, 2)) 1205978Seric { 1215978Seric sleep(2); 1225978Seric printf("getreq: parent waiting\n"); 1235978Seric } 1245978Seric # endif DEBUG 1255978Seric 1267117Seric /* close the port so that others will hang (for a while) */ 1277009Seric (void) close(port); 1287117Seric 1297117Seric /* pick up old zombies; implement load limiting */ 1307117Seric numconnections++; 1317117Seric while (wait3(&status, numconnections < MAXCONNS ? WNOHANG : 0, 0) > 0) 1327117Seric numconnections--; 1334631Seric } 1344631Seric } 1355978Seric /* 1365978Seric ** GETCONNECTION -- make a connection with the outside world 1375978Seric ** 1385978Seric ** Parameters: 1395978Seric ** none. 1405978Seric ** 1415978Seric ** Returns: 1425978Seric ** The port for mail traffic. 1435978Seric ** 1445978Seric ** Side Effects: 1455978Seric ** Waits for a connection. 1465978Seric */ 1475978Seric 1487117Seric #define IPPORT_PLAYPORT 3055 /* random number */ 1497117Seric 1505979Seric struct sockaddr_in SendmailAddress = { AF_INET, IPPORT_SMTP }; 1515978Seric 1525978Seric getconnection() 1535978Seric { 1545978Seric register int s; 1555978Seric struct sockaddr otherend; 1565978Seric 1575978Seric /* 1585978Seric ** Set up the address for the mailer. 1595978Seric */ 1605978Seric 1616058Seric SendmailAddress.sin_addr.s_addr = 0; 1626633Seric SendmailAddress.sin_port = IPPORT_SMTP; 1637117Seric # ifdef DEBUG 1647677Seric if (tTd(15, 15)) 1657117Seric SendmailAddress.sin_port = IPPORT_PLAYPORT; 1667117Seric # endif DEBUG 1677117Seric SendmailAddress.sin_port = htons(SendmailAddress.sin_port); 1685978Seric 1695978Seric /* 1705978Seric ** Try to actually open the connection. 1715978Seric */ 1725978Seric 1735978Seric # ifdef DEBUG 1747677Seric if (tTd(15, 1)) 1756058Seric printf("getconnection\n"); 1765978Seric # endif DEBUG 1775978Seric 1787556Seric for (;;) 1797117Seric { 180*7876Seric int acptcnt; 181*7876Seric 1827556Seric /* get a socket for the SMTP connection */ 1837556Seric s = socket(SOCK_STREAM, 0, &SendmailAddress, SO_ACCEPTCONN); 1847556Seric if (s < 0) 1857556Seric { 1867556Seric /* probably another daemon already */ 1877556Seric syserr("getconnection: can't create socket"); 1887556Seric break; 1897556Seric } 1905978Seric 1915978Seric # ifdef DEBUG 1927677Seric if (tTd(15, 1)) 1937556Seric printf("getconnection: %d\n", s); 1945978Seric # endif DEBUG 1957556Seric 1967556Seric /* wait for a connection */ 197*7876Seric (void) time(&CurTime); 198*7876Seric acptcnt = 0; 1997754Seric do 2007754Seric { 201*7876Seric long now; 202*7876Seric 2037754Seric errno = 0; 2047754Seric (void) accept(s, &otherend); 205*7876Seric (void) time(&now); 206*7876Seric if (now == CurTime) 207*7876Seric { 208*7876Seric if(++acptcnt > 2) 209*7876Seric { 210*7876Seric syserr("wild accept"); 211*7876Seric /* abort(); */ 212*7876Seric break; 213*7876Seric } 214*7876Seric } 215*7876Seric else 216*7876Seric { 217*7876Seric CurTime = now; 218*7876Seric acptcnt = 0; 219*7876Seric } 2207754Seric } while (errno == ETIMEDOUT || errno == EINTR); 2217754Seric if (errno == 0) 2227556Seric break; 2237556Seric syserr("getconnection: accept"); 2247286Seric (void) close(s); 2257556Seric sleep(20); 2267117Seric } 2275978Seric 2285978Seric return (s); 2295978Seric } 2306039Seric /* 2316039Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 2326039Seric ** 2336039Seric ** Parameters: 2346039Seric ** host -- the name of the host. 2356633Seric ** port -- the port number to connect to. 2366039Seric ** outfile -- a pointer to a place to put the outfile 2376039Seric ** descriptor. 2386039Seric ** infile -- ditto for infile. 2396039Seric ** 2406039Seric ** Returns: 2416039Seric ** An exit code telling whether the connection could be 2426039Seric ** made and if not why not. 2436039Seric ** 2446039Seric ** Side Effects: 2456039Seric ** none. 2466039Seric */ 2475978Seric 2486633Seric makeconnection(host, port, outfile, infile) 2496039Seric char *host; 2507286Seric u_short port; 2516039Seric FILE **outfile; 2526039Seric FILE **infile; 2536039Seric { 2546039Seric register int s; 2556039Seric 2566039Seric /* 2576039Seric ** Set up the address for the mailer. 2586039Seric */ 2596039Seric 2606039Seric if ((SendmailAddress.sin_addr.s_addr = rhost(&host)) == -1) 2616039Seric return (EX_NOHOST); 2626633Seric if (port == 0) 2636633Seric port = IPPORT_SMTP; 2647117Seric SendmailAddress.sin_port = htons(port); 2656039Seric 2666039Seric /* 2676039Seric ** Try to actually open the connection. 2686039Seric */ 2696039Seric 2706039Seric # ifdef DEBUG 2717677Seric if (tTd(16, 1)) 2726039Seric printf("makeconnection (%s)\n", host); 2736039Seric # endif DEBUG 2746039Seric 2757009Seric s = socket(SOCK_STREAM, 0, (struct sockaddr_in *) 0, 0); 2766039Seric if (s < 0) 2776039Seric { 2786039Seric syserr("makeconnection: no socket"); 2796039Seric goto failure; 2806039Seric } 2816039Seric 2826039Seric # ifdef DEBUG 2837677Seric if (tTd(16, 1)) 2846039Seric printf("makeconnection: %d\n", s); 2856039Seric # endif DEBUG 2867677Seric (void) fflush(Xscript); /* for debugging */ 2876039Seric if (connect(s, &SendmailAddress) < 0) 2886039Seric { 2896039Seric /* failure, decide if temporary or not */ 2906039Seric failure: 2916039Seric switch (errno) 2926039Seric { 2936039Seric case EISCONN: 2946039Seric case ETIMEDOUT: 2956897Seric case EINPROGRESS: 2966897Seric case EALREADY: 2976897Seric case EADDRINUSE: 2986897Seric case ENETDOWN: 2996897Seric case ENETRESET: 3006897Seric case ENOBUFS: 3017204Seric case ECONNREFUSED: 3026039Seric /* there are others, I'm sure..... */ 3036039Seric return (EX_TEMPFAIL); 3046039Seric 3056039Seric default: 3066039Seric return (EX_UNAVAILABLE); 3076039Seric } 3086039Seric } 3096039Seric 3106039Seric /* connection ok, put it into canonical form */ 3116039Seric *outfile = fdopen(s, "w"); 3126039Seric *infile = fdopen(s, "r"); 3136039Seric 3146039Seric return (0); 3156039Seric } 3166039Seric 3175978Seric #endif DAEMON 318