📄 daemon.c
字号:
/* * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. * * Sendmail * Copyright (c) 1983 Eric P. Allman * Berkeley, California */# include <errno.h># include "sendmail.h"#ifdef DAEMON#include "netdb.h"#include <sys/wait.h>#include <sys/param.h>#include <net/if.h>#include <sys/sockio.h>SCCSID(@(#)daemon.c 1.1 92/07/30 SMI (with daemon mode)); /* from UCB 5.25 4/1/88*//*** DAEMON.C -- routines to use when running as a daemon.**** This entire file is highly dependent on the BSD** interprocess communication primitives. No attempt has** been made to make this file portable to Version 7,** Version 6, MPX files, etc. If you should try such a** thing yourself, I recommend chucking the entire file** and starting from scratch. Basic semantics are:**** getrequests()** Opens a port and initiates a connection.** Returns in a child. Must set InChannel and** OutChannel appropriately.** clrdaemon()** Close any open files associated with getting** the connection; this is used when running the queue,** etc., to avoid having extra file descriptors during** the queue run and to avoid confusing the network** code (if it cares).** makeconnection(host, port, outfile, infile)** Make a connection to the named host on the given** port. Set *outfile and *infile to the files** appropriate for communication. Returns zero on** success, else an exit status and errno describing the** error.** maphostname(hbuf, hbufsize)** Convert the entry in hbuf into a canonical form. It** may not be larger than hbufsize.** lookuphost(host)** Look up the host to determine an address. Return** the address of a struct hostinfo about the host, which** may be modified by the caller if desired.** closeconnection(fd)** Marks the host which we connected to via file desc 'fd'** as closed, so we won't try to reuse the connection.** Note that this does not actually close the file** descriptor. That's the caller's responsibility.*/static struct hostinfo *host_from_fd[NOFILE]; /* Host entry for each */static setuphost(sp, hp) STAB *sp; struct hostent *hp; {# if BSD >= 43 int i; for (i= 0; i < MAXMXHOSTS && *hp->h_addr_list; i++) sp->s_value.sv_host.h_addrlist[ i ] = *(struct in_addr *)(*hp->h_addr_list++); sp->s_value.sv_host.h_addrlist[ i ].s_addr = INADDR_ANY;# else sp->s_value.sv_host.h_addrlist[ 0 ] = *(struct in_addr *)(hp->h_addr); sp->s_value.sv_host.h_addrlist[ 1 ].s_addr = INADDR_ANY;# endif }static jmp_buf NameTimeout;time_t nametime = 90; /* seconds to wait for name server */nametimeout() {longjmp(NameTimeout, 1);}/*** LOOKUPHOST -- determine host address and other remembered info.**** Parameters:** host -- a char * providing a host name or [a.b.c.d].**** Returns:** The address of a struct hostinfo for this host.** The caller may modify h_fd, h_down, and h_open in** this structure. h_addr and h_exists should not be** modified.**** Side Effects:** If the hostname has previously been looked up, the** existing symbol table entry is returned immediately.** Otherwise, a new symbol table entry is created, ** a system-dependent hostname->address lookup is done,** and the new entry is returned.**** Note that for information to be remembered in the** symbol table, the process must do several lookups** without forking and exiting.*/struct hostinfo *lookuphost(host) char *host; /* Host name */{ register struct hostent *hp = (struct hostent *)NULL; extern char *inet_ntoa(); STAB *sp; /* Symbol table entry */ EVENT *ev; sp = stab(host, ST_HOST, ST_ENTER); if (sp->s_value.sv_host.h_valid) { AlreadyKnown = sp->s_value.sv_host.h_down; return &sp->s_value.sv_host; } /* ** Create a new symbol table entry. Initially it is cleared, ** thus h_exists is 0. Ditto for the other flags. ** Then look up the address for the host. ** Accept "[a.b.c.d]" syntax for host name. */ sp->s_value.sv_host.h_valid = 1; if (host[0] == '[') { long hid; register char *p = index(host, ']'); if (p != NULL) { *p = '\0'; hid = inet_addr(&host[1]); *p = ']'; } if (p == NULL || hid == -1) { sp->s_value.sv_host.h_exists = 0; } else { sp->s_value.sv_host.h_addrlist[0].s_addr = hid; sp->s_value.sv_host.h_index = 0; sp->s_value.sv_host.h_exists = 1; } return &sp->s_value.sv_host; /* Return [] entry */ } if (setjmp(NameTimeout) != 0) { sp->s_value.sv_host.h_exists = 1; sp->s_value.sv_host.h_down = 1; sp->s_value.sv_host.h_errno = ENAMESER; return &sp->s_value.sv_host; } ev = setevent(nametime, nametimeout, 0); hp = gethostbyname(host); if (hp != NULL && hp->h_addrtype == AF_INET) { setuphost(sp, hp); sp->s_value.sv_host.h_index = 0; sp->s_value.sv_host.h_exists = 1; } /* * The gethostbyname failed -- in 4.2BSD we just return * a hard error. 4.3BSD gives us more infomation on the failure. * This failure can be returned by the YP library as of 4.1 */ else if (h_errno == TRY_AGAIN) { sp->s_value.sv_host.h_exists = 1; sp->s_value.sv_host.h_down = 1; sp->s_value.sv_host.h_errno = ENAMESER; } clrevent(ev); return &sp->s_value.sv_host; /* Return new entry */}/*** GETREQUESTS -- open mail IPC port and get requests.**** Parameters:** none.**** Returns:** none.**** Side Effects:** Waits until some interesting activity occurs. When** it does, a child is created to process it, and the** parent waits for completion. Return from this** routine is always in the child. The file pointers** "InChannel" and "OutChannel" should be set to point** to the communication channel.*/int DaemonSocket = -1; /* fd describing socket */char *NetName; /* name of home (local?) network */getrequests(){ int t; union wait status; struct sockaddr_in addr; int on = 1; extern reapchild(); /* ** Try to actually open the connection. */ addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(IPPORT_SMTP); /* get a socket for the SMTP connection */ DaemonSocket = socket(AF_INET, SOCK_STREAM, 0); if (DaemonSocket < 0) { /* probably another daemon already */ syserr("getrequests: can't create socket"); severe:# ifdef LOG# ifdef LOG_SALERT if (LogLevel > 0) syslog(LOG_SALERT, "cannot get connection");# else LOG_SALERT if (LogLevel > 0) syslog(LOG_CRIT|LOG_MAIL, "cannot get connection");# endif LOG_SALERT# endif LOG finis(); }#ifdef DEBUG /* turn on network debugging? */ if (tTd(15, 15)) (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);#endif DEBUG (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on); (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on); if (bind(DaemonSocket, &addr, sizeof addr) < 0) { syserr("getrequests: cannot bind"); (void) close(DaemonSocket); goto severe; } if (listen(DaemonSocket, 5) < 0) { syserr("getrequests: cannot listen"); (void) close(DaemonSocket); goto severe; } (void) signal(SIGCHLD, reapchild);# ifdef DEBUG if (tTd(15, 1)) printf("getrequests: %d\n", DaemonSocket);# endif DEBUG# ifdef LOG /* Tell the log that a new daemon has started. */ syslog(LOG_INFO, "network daemon starting");# endif LOG for (;;) { register int pid; auto int lotherend; struct sockaddr_in otherend; extern int RefuseLA; /* see if we are rejecting connections */ while (RefuseLA > 0 && getla() > RefuseLA) sleep(5); /* wait for a connection */ do { errno = 0; lotherend = sizeof otherend; t = accept(DaemonSocket, &otherend, &lotherend); } while (t < 0 && errno == EINTR); if (t < 0) { syserr("getrequests: accept"); sleep(5); continue; } /* ** Create a subprocess to process the mail. */# ifdef DEBUG if (tTd(15, 2)) printf("getrequests: forking (fd = %d)\n", t);# endif DEBUG pid = fork(); if (pid < 0) { syserr("daemon: cannot fork"); sleep(10); (void) close(t); continue; } if (pid == 0) { extern struct hostent *gethostbyaddr(); register struct hostent *hp; char buf[MAXNAME]; EVENT *ev; /* ** CHILD -- return to caller. ** Collect verified idea of sending host. ** Verify calling user id if possible here. */ (void) signal(SIGCHLD, SIG_DFL); /* determine host name with timeout */ if (setjmp(NameTimeout) != 0) { hp = NULL; } else { ev = setevent(nametime, nametimeout, 0); hp = gethostbyaddr( &otherend.sin_addr, sizeof otherend.sin_addr, AF_INET); clrevent(ev); } if (hp != NULL) { (void) strcpy(buf, hp->h_name); if (NetName != NULL && NetName[0] != '\0' && index(hp->h_name, '.') == NULL) { (void) strcat(buf, "."); (void) strcat(buf, NetName); } } else { extern char *inet_ntoa(); /* produce a dotted quad */ (void) sprintf(buf, "[%s]", inet_ntoa(otherend.sin_addr)); } /* should we check for illegal connection here? XXX */ RealHostName = newstr(buf); (void) close(DaemonSocket); setproctitle("From %s", (int)RealHostName); define('r', "TCP", CurEnv); InChannel = fdopen(t, "r"); OutChannel = fdopen(t, "w");# ifdef DEBUG if (tTd(15, 2)) printf("getreq: returning\n");# endif DEBUG# ifdef LOG if (LogLevel > 11) syslog(LOG_DEBUG, "connected, pid=%d", getpid());# endif LOG return; } /* close the port so that others will hang (for a while) */ (void) close(t); } /*NOTREACHED*/}/*** CLRDAEMON -- reset the daemon connection**** Parameters:** none.**** Returns:** none.**** Side Effects:** releases any resources used by the passive daemon.*/clrdaemon(){ if (DaemonSocket >= 0) (void) close(DaemonSocket); DaemonSocket = -1;}/*** MAKECONNECTION -- make a connection to an SMTP socket on another machine.**** Parameters:** host -- the name of the host.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -