⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c.zhh

📁 经典的ppp程序
💻 ZHH
📖 第 1 页 / 共 3 页
字号:
/* * main.c - Point-to-Point Protocol main module * * Copyright (c) 1989 Carnegie Mellon University. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by Carnegie Mellon University.  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'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */#define RCSID	"$Id: main.c,v 1.105 2001/03/12 22:58:59 paulus Exp $"#include <stdio.h>#include <ctype.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <signal.h>#include <errno.h>#include <fcntl.h>#include <syslog.h>#include <netdb.h>#include <utmp.h>#include <pwd.h>#include <setjmp.h>#include <sys/param.h>#include <sys/types.h>#include <sys/wait.h>#include <sys/time.h>#include <sys/resource.h>#include <sys/stat.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include "pppd.h"#include "magic.h"#include "fsm.h"#include "lcp.h"#include "ipcp.h"#ifdef INET6#include "ipv6cp.h"#endif#include "upap.h"#include "chap.h"#include "ccp.h"#include "pathnames.h"#include "tdb.h"#ifdef CBCP_SUPPORT#include "cbcp.h"#endif#ifdef IPX_CHANGE#include "ipxcp.h"#endif /* IPX_CHANGE */#ifdef AT_CHANGE#include "atcp.h"#endifstatic const char rcsid[] = RCSID;/* interface vars */char ifname[32];		/* Interface name */int ifunit;			/* Interface unit number */struct channel *the_channel;char *progname;			/* Name of this program */char hostname[MAXNAMELEN];	/* Our hostname */static char pidfilename[MAXPATHLEN];	/* name of pid file */static char linkpidfile[MAXPATHLEN];	/* name of linkname pid file */char ppp_devnam[MAXPATHLEN];	/* name of PPP tty (maybe ttypx) */uid_t uid;			/* Our real user-id */struct notifier *pidchange = NULL;struct notifier *phasechange = NULL;struct notifier *exitnotify = NULL;struct notifier *sigreceived = NULL;int hungup;			/* terminal has been hung up */int privileged;			/* we're running as real uid root */int need_holdoff;		/* need holdoff period before restarting */int detached;			/* have detached from terminal */volatile int status;		/* exit status for pppd */int unsuccess;			/* # unsuccessful connection attempts */int do_callback;		/* != 0 if we should do callback next */int doing_callback;		/* != 0 if we are doing callback */TDB_CONTEXT *pppdb;		/* database for storing status etc. */char db_key[32];int (*holdoff_hook) __P((void)) = NULL;int (*new_phase_hook) __P((int)) = NULL;static int conn_running;	/* we have a [dis]connector running */static int devfd;		/* fd of underlying device */static int fd_ppp = -1;		/* fd for talking PPP */static int fd_loop;		/* fd for getting demand-dial packets */int phase;			/* where the link is at */int kill_link;int open_ccp_flag;int listen_time;int got_sigusr2;int got_sigterm;int got_sighup;static int waiting;static sigjmp_buf sigjmp;char **script_env;		/* Env. variable values for scripts */int s_env_nalloc;		/* # words avail at script_env */u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */static int n_children;		/* # child processes still running */static int got_sigchld;		/* set if we have received a SIGCHLD */int privopen;			/* don't lock, open device as root */char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n";GIDSET_TYPE groups[NGROUPS_MAX];/* groups the user is in */int ngroups;			/* How many groups valid in groups */static struct timeval start_time;	/* Time when link was started. */struct pppd_stats link_stats;int link_connect_time;int link_stats_valid;/* * We maintain a list of child process pids and * functions to call when they exit. */struct subprocess {    pid_t	pid;    char	*prog;    void	(*done) __P((void *));    void	*arg;    struct subprocess *next;};static struct subprocess *children;/* Prototypes for procedures local to this file. */static void setup_signals __P((void));static void create_pidfile __P((void));static void create_linkpidfile __P((void));static void cleanup __P((void));static void get_input __P((void));static void calltimeout __P((void));static struct timeval *timeleft __P((struct timeval *));static void kill_my_pg __P((int));static void hup __P((int));static void term __P((int));static void chld __P((int));static void toggle_debug __P((int));static void open_ccp __P((int));static void bad_signal __P((int));static void holdoff_end __P((void *));static int reap_kids __P((int waitfor));static void update_db_entry __P((void));static void add_db_key __P((const char *));static void delete_db_key __P((const char *));static void cleanup_db __P((void));static void handle_events __P((void));extern	char	*ttyname __P((int));extern	char	*getlogin __P((void));int main __P((int, char *[]));#ifdef ultrix#undef	O_NONBLOCK#define	O_NONBLOCK	O_NDELAY#endif#ifdef ULTRIX#define setlogmask(x)#endif/* * PPP Data Link Layer "protocol" table. * One entry per supported protocol. * The last entry must be NULL. */struct protent *protocols[] = {    &lcp_protent,    &pap_protent,    &chap_protent,#ifdef CBCP_SUPPORT    &cbcp_protent,#endif    &ipcp_protent,#ifdef INET6    &ipv6cp_protent,#endif    &ccp_protent,#ifdef IPX_CHANGE    &ipxcp_protent,#endif#ifdef AT_CHANGE    &atcp_protent,#endif    NULL};/* * If PPP_DRV_NAME is not defined, use the default "ppp" as the device name. */#if !defined(PPP_DRV_NAME)#define PPP_DRV_NAME	"ppp"#endif /* !defined(PPP_DRV_NAME) */intmain(argc, argv)    int argc;    char *argv[];{    int i, t;    char *p;    struct passwd *pw;    struct protent *protp;    char numbuf[16];    new_phase(PHASE_INITIALIZE);    /*     * Ensure that fds 0, 1, 2 are open, to /dev/null if nowhere else.     * This way we can close 0, 1, 2 in detach() without clobbering     * a fd that we are using.     */    if ((i = open("/dev/null", O_RDWR)) >= 0) {	while (0 <= i && i <= 2)	    i = dup(i);	if (i >= 0)	    close(i);    }    script_env = NULL;    /* Initialize syslog facilities */    reopen_log();    if (gethostname(hostname, MAXNAMELEN) < 0 ) {	option_error("Couldn't get hostname: %m");	exit(1);    }    hostname[MAXNAMELEN-1] = 0;    /* make sure we don't create world or group writable files. */    umask(umask(0777) | 022);    uid = getuid();    privileged = uid == 0;    slprintf(numbuf, sizeof(numbuf), "%d", uid);    script_setenv("ORIG_UID", numbuf, 0);    ngroups = getgroups(NGROUPS_MAX, groups);    /*     * Initialize magic number generator now so that protocols may     * use magic numbers in initialization.     */    magic_init();    /*     * Initialize each protocol.     */    for (i = 0; (protp = protocols[i]) != NULL; ++i)        (*protp->init)(0);    /*     * Initialize the default channel.     */    tty_init();    progname = *argv;    /*     * Parse, in order, the system options file, the user's options file,     * and the command line arguments.     */    if (!options_from_file(_PATH_SYSOPTIONS, !privileged, 0, 1)	|| !options_from_user()	|| !parse_args(argc-1, argv+1))	exit(EXIT_OPTION_ERROR);    devnam_fixed = 1;		/* can no longer change device name */    /*     * Work out the device name, if it hasn't already been specified,     * and parse the tty's options file.     */    if (the_channel->process_extra_options)	(*the_channel->process_extra_options)();    if (debug)	setlogmask(LOG_UPTO(LOG_DEBUG));    /*     * Check that we are running as root.     */    if (geteuid() != 0) {	option_error("must be root to run %s, since it is not setuid-root",		     argv[0]);	exit(EXIT_NOT_ROOT);    }    if (!ppp_available()) {	option_error("%s", no_ppp_msg);	exit(EXIT_NO_KERNEL_SUPPORT);    }    /*     * Check that the options given are valid and consistent.     */    check_options();    if (!sys_check_options())	exit(EXIT_OPTION_ERROR);    auth_check_options();#ifdef HAVE_MULTILINK    mp_check_options();#endif    for (i = 0; (protp = protocols[i]) != NULL; ++i)	if (protp->check_options != NULL)	    (*protp->check_options)();    if (the_channel->check_options)	(*the_channel->check_options)();    if (dump_options || dryrun) {	init_pr_log(NULL, LOG_INFO);	print_options(pr_log, NULL);	end_pr_log();	if (dryrun)	    die(0);    }    /*     * Initialize system-dependent stuff.     */    sys_init();    pppdb = tdb_open(_PATH_PPPDB, 0, 0, O_RDWR|O_CREAT, 0644);    if (pppdb != NULL) {	slprintf(db_key, sizeof(db_key), "pppd%d", getpid());	update_db_entry();    } else {	warn("Warning: couldn't open ppp database %s", _PATH_PPPDB);	if (multilink) {	    warn("Warning: disabling multilink");	    multilink = 0;	}    }    /*     * Detach ourselves from the terminal, if required,     * and identify who is running us.     */    if (!nodetach && !updetach)	detach();    p = getlogin();    if (p == NULL) {	pw = getpwuid(uid);	if (pw != NULL && pw->pw_name != NULL)	    p = pw->pw_name;	else	    p = "(unknown)";    }    syslog(LOG_NOTICE, "pppd %s started by %s, uid %d", VERSION, p, uid);    script_setenv("PPPLOGNAME", p, 0);    if (devnam[0])	script_setenv("DEVICE", devnam, 1);    slprintf(numbuf, sizeof(numbuf), "%d", getpid());    script_setenv("PPPD_PID", numbuf, 1);    setup_signals();    waiting = 0;    create_linkpidfile();    /*     * If we're doing dial-on-demand, set up the interface now.     */    if (demand) {	/*	 * Open the loopback channel and set it up to be the ppp interface.	 */	tdb_writelock(pppdb);	fd_loop = open_ppp_loopback();	set_ifunit(1);	tdb_writeunlock(pppdb);	/*	 * Configure the interface and mark it up, etc.	 */	demand_conf();    }    do_callback = 0;    for (;;) {	listen_time = 0;	need_holdoff = 1;	devfd = -1;	status = EXIT_OK;	++unsuccess;	doing_callback = do_callback;	do_callback = 0;	if (demand && !doing_callback) {	    /*	     * Don't do anything until we see some activity.	     */	    new_phase(PHASE_DORMANT);	    demand_unblock();	    add_fd(fd_loop);	    for (;;) {		handle_events();		if (kill_link && !persist)		    break;		if (get_loop_output())		    break;	    }	    remove_fd(fd_loop);	    if (kill_link && !persist)		break;	    /*	     * Now we want to bring up the link.	     */	    demand_block();	    info("Starting link");	}	new_phase(PHASE_SERIALCONN);	devfd = the_channel->connect();	if (devfd < 0)	    goto fail;	/* set up the serial device as a ppp interface */	tdb_writelock(pppdb);	fd_ppp = the_channel->establish_ppp(devfd);	if (fd_ppp < 0) {	    tdb_writeunlock(pppdb);	    status = EXIT_FATAL_ERROR;	    goto disconnect;	}	if (!demand && ifunit >= 0)	    set_ifunit(1);	tdb_writeunlock(pppdb);	/*	 * Start opening the connection and wait for	 * incoming events (reply, timeout, etc.).	 */	notice("Connect: %s <--> %s", ifname, ppp_devnam);	gettimeofday(&start_time, NULL);	link_stats_valid = 0;	script_unsetenv("CONNECT_TIME");	script_unsetenv("BYTES_SENT");	script_unsetenv("BYTES_RCVD");	lcp_lowerup(0);	add_fd(fd_ppp);	lcp_open(0);		/* Start protocol */	status = EXIT_NEGOTIATION_FAILED;	new_phase(PHASE_ESTABLISH);	while (phase != PHASE_DEAD) {	    handle_events();	    get_input();	    if (kill_link)		lcp_close(0, "User request");	    if (open_ccp_flag) {		if (phase == PHASE_NETWORK || phase == PHASE_RUNNING) {		    ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */		    (*ccp_protent.open)(0);		}	    }	}	/*	 * Print connect time and statistics.	 */	if (link_stats_valid) {	    int t = (link_connect_time + 5) / 6;    /* 1/10ths of minutes */	    info("Connect time %d.%d minutes.", t/10, t%10);	    info("Sent %u bytes, received %u bytes.",		 link_stats.bytes_out, link_stats.bytes_in);	}	/*	 * Delete pid file before disestablishing ppp.  Otherwise it	 * can happen that another pppd gets the same unit and then	 * we delete its pid file.	 */	if (!demand) {	    if (pidfilename[0] != 0		&& unlink(pidfilename) < 0 && errno != ENOENT) 		warn("unable to delete pid file %s: %m", pidfilename);	    pidfilename[0] = 0;	}	/*	 * If we may want to bring the link up again, transfer	 * the ppp unit back to the loopback.  Set the	 * real serial device back to its normal mode of operation.	 */	remove_fd(fd_ppp);	clean_check();	the_channel->disestablish_ppp(devfd);	fd_ppp = -1;	if (!hungup)	    lcp_lowerdown(0);	if (!demand)	    script_unsetenv("IFNAME");	/*	 * Run disconnector script, if requested.	 * XXX we may not be able to do this if the line has hung up!	 */    disconnect:	new_phase(PHASE_DISCONNECT);	the_channel->disconnect();    fail:	if (the_channel->cleanup)	    (*the_channel->cleanup)();	if (!demand) {	    if (pidfilename[0] != 0		&& unlink(pidfilename) < 0 && errno != ENOENT) 		warn("unable to delete pid file %s: %m", pidfilename);	    pidfilename[0] = 0;	}	if (!persist || (maxfail > 0 && unsuccess >= maxfail))	    break;	if (demand)	    demand_discard();	t = need_holdoff? holdoff: 0;	if (holdoff_hook)	    t = (*holdoff_hook)();	if (t > 0) {	    new_phase(PHASE_HOLDOFF);	    TIMEOUT(holdoff_end, NULL, t);	    do {		handle_events();		if (kill_link)		    new_phase(PHASE_DORMANT); /* allow signal to end holdoff */	    } while (phase == PHASE_HOLDOFF);	    if (!persist)		break;	}    }    /* Wait for scripts to finish */    /* XXX should have a timeout here */    while (n_children > 0) {	if (debug) {	    struct subprocess *chp;	    dbglog("Waiting for %d child processes...", n_children);	    for (chp = children; chp != NULL; chp = chp->next)		dbglog("  script %s, pid %d", chp->prog, chp->pid);	}	if (reap_kids(1) < 0)	    break;    }    die(status);    return 0;}/* * handle_events - wait for something to happen and respond to it. */static voidhandle_events(){    struct timeval timo;    sigset_t mask;    kill_link = open_ccp_flag = 0;    if (sigsetjmp(sigjmp, 1) == 0) {	sigprocmask(SIG_BLOCK, &mask, NULL);	if (got_sighup || got_sigterm || got_sigusr2 || got_sigchld) {	    sigprocmask(SIG_UNBLOCK, &mask, NULL);	} else {	    waiting = 1;	    sigprocmask(SIG_UNBLOCK, &mask, NULL);	    wait_input(timeleft(&timo));	}    }    waiting = 0;    calltimeout();    if (got_sighup) {	kill_link = 1;	got_sighup = 0;	if (status != EXIT_HANGUP)	    status = EXIT_USER_REQUEST;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -