diff options
Diffstat (limited to 'pppd_plugin/src/pptp_callmgr.c')
-rw-r--r-- | pppd_plugin/src/pptp_callmgr.c | 403 |
1 files changed, 0 insertions, 403 deletions
diff --git a/pppd_plugin/src/pptp_callmgr.c b/pppd_plugin/src/pptp_callmgr.c deleted file mode 100644 index 20bb7369..00000000 --- a/pppd_plugin/src/pptp_callmgr.c +++ /dev/null @@ -1,403 +0,0 @@ -/* 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 */ -extern int call_ID; - -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=NULL; - int volatile window=10; - //int volatile call_id=0; - /* 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; - for(i=2; i<argc; i++) - { - //log("%s",argv[i]); - if (strcmp(argv[i],"--phone")==0 && i+1<argc) phonenr=argv[++i]; - else if (strcmp(argv[i],"--window")==0 && i+1<argc) window=atoi(argv[++i]); - else if (strcmp(argv[i],"--call_id")==0 && i+1<argc) call_ID=atoi(argv[++i]); - } - if (inet_aton(argv[1], &inetaddr) == 0) - fatal("Invalid IP address: %s", argv[1]); - log("IP: %s\n",inet_ntoa(inetaddr)); - /* Step 1: Open sockets. */ - if ((inet_sock = open_inetsock(inetaddr)) < 0) - fatal("Could not open control connection to %s", argv[1]); - log("control connection"); - 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. */ - log("unix_sock"); - - 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_ID,call_callback, phonenr,window); - /* 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 = dirnamex(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:%i", remoteaddr,call_ID); -} |