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

📄 pptp_callmgr.c

📁 this is a linux pptp software
💻 C
字号:
/* pptp_callmgr.c ... Call manager for PPTP connections. *                    Handles TCP port 1723 protocol. *                    C. Scott Ananian <cananian@alumni.princeton.edu> * * $Id: pptp_callmgr.c,v 1.20 2005/03/31 07:42:39 quozl Exp $ */#include <signal.h>#include <sys/time.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/un.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <setjmp.h>#include <stdio.h>#include <errno.h>#include "pptp_callmgr.h"#include "pptp_ctrl.h"#include "pptp_msg.h"#include "dirutil.h"#include "vector.h"#include "util.h"extern struct in_addr localbind; /* from pptp.c */int open_inetsock(struct in_addr inetaddr);int open_unixsock(struct in_addr inetaddr);void close_inetsock(int fd, struct in_addr inetaddr);void close_unixsock(int fd, struct in_addr inetaddr);sigjmp_buf callmgr_env;void callmgr_sighandler(int sig) {    /* TODO: according to signal(2), siglongjmp() is unsafe used here */    siglongjmp (callmgr_env, 1);}void callmgr_do_nothing(int sig) {    /* do nothing signal handler */}struct local_callinfo {    int unix_sock;    pid_t pid[2];};struct local_conninfo {    VECTOR * call_list;    fd_set * call_set;};/* Call callback */void call_callback(PPTP_CONN *conn, PPTP_CALL *call, enum call_state state){    struct local_callinfo *lci;    struct local_conninfo *conninfo;    u_int16_t call_id[2];    switch(state) {        case CALL_OPEN_DONE:            /* okey dokey.  This means that the call_id and peer_call_id are             * now valid, so lets send them on to our friends who requested             * this call.  */            lci = pptp_call_closure_get(conn, call); assert(lci != NULL);            pptp_call_get_ids(conn, call, &call_id[0], &call_id[1]);            write(lci->unix_sock, &call_id, sizeof(call_id));            /* Our duty to the fatherland is now complete. */            break;        case CALL_OPEN_FAIL:        case CALL_CLOSE_RQST:        case CALL_CLOSE_DONE:            /* don't need to do anything here, except make sure tables             * are sync'ed */            log("Closing connection (call state)");            conninfo = pptp_conn_closure_get(conn);            lci = pptp_call_closure_get(conn, call);             assert(lci != NULL && conninfo != NULL);            if (vector_contains(conninfo->call_list, lci->unix_sock)) {                vector_remove(conninfo->call_list, lci->unix_sock);                close(lci->unix_sock);                FD_CLR(lci->unix_sock, conninfo->call_set);                if(lci->pid[0] > 1) kill(lci->pid[0], SIGTERM);                if(lci->pid[1] > 1) kill(lci->pid[1], SIGTERM);            }            break;        default:            log("Unhandled call callback state [%d].", (int) state);            break;    }}/****************************************************************************** * NOTE ABOUT 'VOLATILE': * several variables here get a volatile qualifier to silence warnings * from older (before 3.0) gccs. if the longjmp stuff is removed, * the volatile qualifiers should be removed as well. *****************************************************************************//*** Call Manager *************************************************************/int callmgr_main(int argc, char **argv, char **envp){    struct in_addr inetaddr;    int inet_sock, unix_sock;    fd_set call_set;    PPTP_CONN * conn;    VECTOR * call_list;    int max_fd = 0;    volatile int first = 1;    int retval;    int i;    char * volatile phonenr;    /* Step 0: Check arguments */    if (argc < 2)         fatal("Usage: %s ip.add.ress.here [--phone <phone number>]", argv[0]);    phonenr = argc == 3 ? argv[2] : NULL;    if (inet_aton(argv[1], &inetaddr) == 0)        fatal("Invalid IP address: %s", argv[1]);    /* Step 1: Open sockets. */    if ((inet_sock = open_inetsock(inetaddr)) < 0)        fatal("Could not open control connection to %s", argv[1]);    if ((unix_sock = open_unixsock(inetaddr)) < 0)        fatal("Could not open unix socket for %s", argv[1]);    /* Step 1b: FORK and return status to calling process. */    switch (fork()) {        case 0: /* child. stick around. */            break;        case -1: /* failure.  Fatal. */            fatal("Could not fork.");        default: /* Parent. Return status to caller. */            exit(0);    }    /* re-open stderr as /dev/null to release it */    file2fd("/dev/null", "wb", STDERR_FILENO);    /* Step 1c: Clean up unix socket on TERM */    if (sigsetjmp(callmgr_env, 1) != 0)        goto cleanup;    signal(SIGINT, callmgr_sighandler);    signal(SIGTERM, callmgr_sighandler);    signal(SIGPIPE, callmgr_do_nothing);    signal(SIGUSR1, callmgr_do_nothing); /* signal state change                                            wake up accept */    /* Step 2: Open control connection and register callback */    if ((conn = pptp_conn_open(inet_sock, 1, NULL/* callback */)) == NULL) {        close(unix_sock); close(inet_sock); fatal("Could not open connection.");    }    FD_ZERO(&call_set);    call_list = vector_create();    {         struct local_conninfo *conninfo = malloc(sizeof(*conninfo));        if (conninfo == NULL) {            close(unix_sock); close(inet_sock); fatal("No memory.");        }        conninfo->call_list = call_list;        conninfo->call_set  = &call_set;        pptp_conn_closure_put(conn, conninfo);    }    if (sigsetjmp(callmgr_env, 1) != 0) goto shutdown;    /* Step 3: Get FD_SETs */    max_fd = unix_sock;    do {        int rc;        fd_set read_set = call_set, write_set;        FD_ZERO (&write_set);        if (pptp_conn_established(conn)) {	  FD_SET (unix_sock, &read_set);	  if (unix_sock > max_fd) max_fd = unix_sock;	}        pptp_fd_set(conn, &read_set, &write_set, &max_fd);        for (; max_fd > 0 ; max_fd--) {            if (FD_ISSET (max_fd, &read_set) ||                    FD_ISSET (max_fd, &write_set))                break;        }        /* Step 4: Wait on INET or UNIX event */        if ((rc = select(max_fd + 1, &read_set, &write_set, NULL, NULL)) <0) {	  if (errno == EBADF) break;	  /* a signal or somesuch. */	  continue;	}        /* Step 5a: Handle INET events */        rc = pptp_dispatch(conn, &read_set, &write_set);	if (rc < 0)	    break;        /* Step 5b: Handle new connection to UNIX socket */        if (FD_ISSET(unix_sock, &read_set)) {            /* New call! */            struct sockaddr_un from;            int len = sizeof(from);            PPTP_CALL * call;            struct local_callinfo *lci;            int s;            /* Accept the socket */            FD_CLR (unix_sock, &read_set);            if ((s = accept(unix_sock, (struct sockaddr *) &from, &len)) < 0) {                warn("Socket not accepted: %s", strerror(errno));                goto skip_accept;            }            /* Allocate memory for local call information structure. */            if ((lci = malloc(sizeof(*lci))) == NULL) {                warn("Out of memory."); close(s); goto skip_accept;            }            lci->unix_sock = s;            /* Give the initiator time to write the PIDs while we open             * the call */            call = pptp_call_open(conn, call_callback, phonenr);            /* Read and store the associated pids */            read(s, &lci->pid[0], sizeof(lci->pid[0]));            read(s, &lci->pid[1], sizeof(lci->pid[1]));            /* associate the local information with the call */            pptp_call_closure_put(conn, call, (void *) lci);            /* The rest is done on callback. */            /* Keep alive; wait for close */            retval = vector_insert(call_list, s, call); assert(retval);            if (s > max_fd) max_fd = s;            FD_SET(s, &call_set);            first = 0;        }skip_accept: /* Step 5c: Handle socket close */        for (i = 0; i < max_fd + 1; i++)            if (FD_ISSET(i, &read_set)) {                /* close it */                PPTP_CALL * call;                retval = vector_search(call_list, i, &call);                if (retval) {                    struct local_callinfo *lci =                        pptp_call_closure_get(conn, call);                    log("Closing connection (unhandled)");                    if(lci->pid[0] > 1) kill(lci->pid[0], SIGTERM);                    if(lci->pid[1] > 1) kill(lci->pid[1], SIGTERM);                    free(lci);                    /* soft shutdown.  Callback will do hard shutdown later */                    pptp_call_close(conn, call);                    vector_remove(call_list, i);                }                FD_CLR(i, &call_set);                close(i);            }    } while (vector_size(call_list) > 0 || first);shutdown:    {        int rc;        fd_set read_set, write_set;        struct timeval tv;	signal(SIGINT, callmgr_do_nothing);	signal(SIGTERM, callmgr_do_nothing);        /* warn("Shutdown"); */        /* kill all open calls */        for (i = 0; i < vector_size(call_list); i++) {            PPTP_CALL *call = vector_get_Nth(call_list, i);            struct local_callinfo *lci = pptp_call_closure_get(conn, call);            log("Closing connection (shutdown)");            pptp_call_close(conn, call);            if(lci->pid[0] > 1) kill(lci->pid[0], SIGTERM);            if(lci->pid[1] > 1) kill(lci->pid[1], SIGTERM);        }        /* attempt to dispatch these messages */        FD_ZERO(&read_set);        FD_ZERO(&write_set);        pptp_fd_set(conn, &read_set, &write_set, &max_fd);	tv.tv_sec = 0;	tv.tv_usec = 0;	select(max_fd + 1, &read_set, &write_set, NULL, &tv);        rc = pptp_dispatch(conn, &read_set, &write_set);	if (rc > 0) {	  /* wait for a respond, a timeout because there might not be one */ 	  FD_ZERO(&read_set);	  FD_ZERO(&write_set);	  pptp_fd_set(conn, &read_set, &write_set, &max_fd);	  tv.tv_sec = 2;	  tv.tv_usec = 0;	  select(max_fd + 1, &read_set, &write_set, NULL, &tv);	  rc = pptp_dispatch(conn, &read_set, &write_set);	  if (rc > 0) {	    if (i > 0) sleep(2);	    /* no more open calls.  Close the connection. */	    pptp_conn_close(conn, PPTP_STOP_LOCAL_SHUTDOWN);	    /* wait for a respond, a timeout because there might not be one */ 	    FD_ZERO(&read_set);	    FD_ZERO(&write_set);	    pptp_fd_set(conn, &read_set, &write_set, &max_fd);	    tv.tv_sec = 2;	    tv.tv_usec = 0;	    select(max_fd + 1, &read_set, &write_set, NULL, &tv);	    pptp_dispatch(conn, &read_set, &write_set);	    if (rc > 0) sleep(2);	  }	}        /* with extreme prejudice */        pptp_conn_destroy(conn);        vector_destroy(call_list);    }cleanup:    signal(SIGINT, callmgr_do_nothing);    signal(SIGTERM, callmgr_do_nothing);    close_inetsock(inet_sock, inetaddr);    close_unixsock(unix_sock, inetaddr);    return 0;}/*** open_inetsock ************************************************************/int open_inetsock(struct in_addr inetaddr){    struct sockaddr_in dest, src;    int s;    dest.sin_family = AF_INET;    dest.sin_port   = htons(PPTP_PORT);    dest.sin_addr   = inetaddr;    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {        warn("socket: %s", strerror(errno));        return s;    }    if (localbind.s_addr != INADDR_NONE) {        bzero(&src, sizeof(src));        src.sin_family = AF_INET;        src.sin_addr   = localbind;        if (bind(s, (struct sockaddr *) &src, sizeof(src)) != 0) {            warn("bind: %s", strerror(errno));            close(s); return -1;        }    }    if (connect(s, (struct sockaddr *) &dest, sizeof(dest)) < 0) {        warn("connect: %s", strerror(errno));        close(s); return -1;    }    return s;}/*** open_unixsock ************************************************************/int open_unixsock(struct in_addr inetaddr){    struct sockaddr_un where;    struct stat st;    char *dir;    int s;    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {        warn("socket: %s", strerror(errno));        return s;    }    callmgr_name_unixsock( &where, inetaddr, localbind);    if (stat(where.sun_path, &st) >= 0) {        warn("Call manager for %s is already running.", inet_ntoa(inetaddr));        close(s); return -1;    }    /* Make sure path is valid. */    dir = dirname(where.sun_path);    if (!make_valid_path(dir, 0770))        fatal("Could not make path to %s: %s", where.sun_path, strerror(errno));    free(dir);    if (bind(s, (struct sockaddr *) &where, sizeof(where)) < 0) {        warn("bind: %s", strerror(errno));        close(s); return -1;    }    chmod(where.sun_path, 0777);    listen(s, 127);    return s;}/*** close_inetsock ***********************************************************/void close_inetsock(int fd, struct in_addr inetaddr){    close(fd);}/*** close_unixsock ***********************************************************/void close_unixsock(int fd, struct in_addr inetaddr){    struct sockaddr_un where;    close(fd);    callmgr_name_unixsock(&where, inetaddr, localbind);    unlink(where.sun_path);}/*** make a unix socket address ***********************************************/void callmgr_name_unixsock(struct sockaddr_un *where, 			   struct in_addr inetaddr,			   struct in_addr localbind){    char localaddr[16], remoteaddr[16];    where->sun_family = AF_UNIX;    strncpy(localaddr,  inet_ntoa(localbind), 16);    strncpy(remoteaddr, inet_ntoa(inetaddr),  16);    snprintf(where->sun_path, sizeof(where->sun_path),            PPTP_SOCKET_PREFIX "%s:%s", localaddr, remoteaddr);}

⌨️ 快捷键说明

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