• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/accel-pptpd/pppd_plugin/src/
1/* pptp_callmgr.c ... Call manager for PPTP connections.
2 *                    Handles TCP port 1723 protocol.
3 *                    C. Scott Ananian <cananian@alumni.princeton.edu>
4 *
5 * $Id: pptp_callmgr.c,v 1.20 2005/03/31 07:42:39 quozl Exp $
6 */
7#include <signal.h>
8#include <sys/time.h>
9#include <sys/types.h>
10#include <sys/stat.h>
11#include <sys/socket.h>
12#include <netinet/in.h>
13#include <arpa/inet.h>
14#include <sys/un.h>
15#include <unistd.h>
16#include <stdlib.h>
17#include <string.h>
18#include <assert.h>
19#include <setjmp.h>
20#include <stdio.h>
21#include <errno.h>
22#include "pptp_callmgr.h"
23#include "pptp_ctrl.h"
24#include "pptp_msg.h"
25#include "dirutil.h"
26#include "vector.h"
27#include "util.h"
28
29extern struct in_addr localbind; /* from pptp.c */
30extern int call_ID;
31
32int open_inetsock(struct in_addr inetaddr);
33int open_unixsock(struct in_addr inetaddr);
34void close_inetsock(int fd, struct in_addr inetaddr);
35void close_unixsock(int fd, struct in_addr inetaddr);
36
37sigjmp_buf callmgr_env;
38
39void callmgr_sighandler(int sig) {
40    /* TODO: according to signal(2), siglongjmp() is unsafe used here */
41    siglongjmp (callmgr_env, 1);
42}
43
44void callmgr_do_nothing(int sig) {
45    /* do nothing signal handler */
46}
47
48struct local_callinfo {
49    int unix_sock;
50    pid_t pid[2];
51};
52
53struct local_conninfo {
54    VECTOR * call_list;
55    fd_set * call_set;
56};
57
58/* Call callback */
59void call_callback(PPTP_CONN *conn, PPTP_CALL *call, enum call_state state)
60{
61    struct local_callinfo *lci;
62    struct local_conninfo *conninfo;
63    u_int16_t call_id[2];
64    switch(state) {
65        case CALL_OPEN_DONE:
66            /* okey dokey.  This means that the call_id and peer_call_id are
67             * now valid, so lets send them on to our friends who requested
68             * this call.  */
69            lci = pptp_call_closure_get(conn, call); assert(lci != NULL);
70            pptp_call_get_ids(conn, call, &call_id[0], &call_id[1]);
71            write(lci->unix_sock, &call_id, sizeof(call_id));
72            /* Our duty to the fatherland is now complete. */
73            break;
74        case CALL_OPEN_FAIL:
75        case CALL_CLOSE_RQST:
76        case CALL_CLOSE_DONE:
77            /* don't need to do anything here, except make sure tables
78             * are sync'ed */
79            log("Closing connection (call state)");
80            conninfo = pptp_conn_closure_get(conn);
81            lci = pptp_call_closure_get(conn, call);
82            assert(lci != NULL && conninfo != NULL);
83            if (vector_contains(conninfo->call_list, lci->unix_sock)) {
84                vector_remove(conninfo->call_list, lci->unix_sock);
85                close(lci->unix_sock);
86                FD_CLR(lci->unix_sock, conninfo->call_set);
87                //if(lci->pid[0] > 1) kill(lci->pid[0], SIGTERM);
88                //if(lci->pid[1] > 1) kill(lci->pid[1], SIGTERM);
89            }
90            break;
91        default:
92            log("Unhandled call callback state [%d].", (int) state);
93            break;
94    }
95}
96
97/******************************************************************************
98 * NOTE ABOUT 'VOLATILE':
99 * several variables here get a volatile qualifier to silence warnings
100 * from older (before 3.0) gccs. if the longjmp stuff is removed,
101 * the volatile qualifiers should be removed as well.
102 *****************************************************************************/
103
104/*** Call Manager *************************************************************/
105int callmgr_main(int argc, char **argv, char **envp)
106{
107    struct in_addr inetaddr;
108    int inet_sock, unix_sock;
109    fd_set call_set;
110    PPTP_CONN * conn;
111    VECTOR * call_list;
112    int max_fd = 0;
113    volatile int first = 1;
114    int retval;
115    int i;
116    char * volatile phonenr=NULL;
117    int volatile window=10;
118    //int volatile call_id=0;
119    /* Step 0: Check arguments */
120    if (argc < 2)
121        fatal("Usage: %s ip.add.ress.here [--phone <phone number>]", argv[0]);
122    //phonenr = argc == 3 ? argv[2] : NULL;
123    for(i=2; i<argc; i++)
124    {
125    	//log("%s",argv[i]);
126    	if (strcmp(argv[i],"--phone")==0 && i+1<argc) phonenr=argv[++i];
127    	else if (strcmp(argv[i],"--window")==0 && i+1<argc) window=atoi(argv[++i]);
128    	else if (strcmp(argv[i],"--call_id")==0 && i+1<argc) call_ID=atoi(argv[++i]);
129    }
130    if (inet_aton(argv[1], &inetaddr) == 0)
131        fatal("Invalid IP address: %s", argv[1]);
132     log("IP: %s\n",inet_ntoa(inetaddr));
133    /* Step 1: Open sockets. */
134    if ((inet_sock = open_inetsock(inetaddr)) < 0)
135        fatal("Could not open control connection to %s", argv[1]);
136    log("control connection");
137    if ((unix_sock = open_unixsock(inetaddr)) < 0)
138        fatal("Could not open unix socket for %s", argv[1]);
139    /* Step 1b: FORK and return status to calling process. */
140    log("unix_sock");
141
142    switch (fork()) {
143        case 0: /* child. stick around. */
144            break;
145        case -1: /* failure.  Fatal. */
146            fatal("Could not fork.");
147        default: /* Parent. Return status to caller. */
148            exit(0);
149    }
150    /* re-open stderr as /dev/null to release it */
151    file2fd("/dev/null", "wb", STDERR_FILENO);
152    /* Step 1c: Clean up unix socket on TERM */
153    if (sigsetjmp(callmgr_env, 1) != 0)
154        goto cleanup;
155    signal(SIGINT, callmgr_sighandler);
156    signal(SIGTERM, callmgr_sighandler);
157    signal(SIGPIPE, callmgr_do_nothing);
158    signal(SIGUSR1, callmgr_do_nothing); /* signal state change
159                                            wake up accept */
160    /* Step 2: Open control connection and register callback */
161    if ((conn = pptp_conn_open(inet_sock, 1, NULL/* callback */)) == NULL) {
162        close(unix_sock); close(inet_sock); fatal("Could not open connection.");
163    }
164    FD_ZERO(&call_set);
165    call_list = vector_create();
166    {
167        struct local_conninfo *conninfo = malloc(sizeof(*conninfo));
168        if (conninfo == NULL) {
169            close(unix_sock); close(inet_sock); fatal("No memory.");
170        }
171        conninfo->call_list = call_list;
172        conninfo->call_set  = &call_set;
173        pptp_conn_closure_put(conn, conninfo);
174    }
175    if (sigsetjmp(callmgr_env, 1) != 0) goto shutdown;
176    /* Step 3: Get FD_SETs */
177    max_fd = unix_sock;
178    do {
179        int rc;
180        fd_set read_set = call_set, write_set;
181        FD_ZERO (&write_set);
182        if (pptp_conn_established(conn)) {
183	  FD_SET (unix_sock, &read_set);
184	  if (unix_sock > max_fd) max_fd = unix_sock;
185	}
186        pptp_fd_set(conn, &read_set, &write_set, &max_fd);
187        for (; max_fd > 0 ; max_fd--) {
188            if (FD_ISSET (max_fd, &read_set) ||
189                    FD_ISSET (max_fd, &write_set))
190                break;
191        }
192        /* Step 4: Wait on INET or UNIX event */
193        if ((rc = select(max_fd + 1, &read_set, &write_set, NULL, NULL)) <0) {
194	  if (errno == EBADF) break;
195	  /* a signal or somesuch. */
196	  continue;
197	}
198        /* Step 5a: Handle INET events */
199        rc = pptp_dispatch(conn, &read_set, &write_set);
200	if (rc < 0)
201	    break;
202        /* Step 5b: Handle new connection to UNIX socket */
203        if (FD_ISSET(unix_sock, &read_set)) {
204            /* New call! */
205            struct sockaddr_un from;
206            int len = sizeof(from);
207            PPTP_CALL * call;
208            struct local_callinfo *lci;
209            int s;
210            /* Accept the socket */
211            FD_CLR (unix_sock, &read_set);
212            if ((s = accept(unix_sock, (struct sockaddr *) &from, &len)) < 0) {
213                warn("Socket not accepted: %s", strerror(errno));
214                goto skip_accept;
215            }
216            /* Allocate memory for local call information structure. */
217            if ((lci = malloc(sizeof(*lci))) == NULL) {
218                warn("Out of memory."); close(s); goto skip_accept;
219            }
220            lci->unix_sock = s;
221            /* Give the initiator time to write the PIDs while we open
222             * the call */
223            call = pptp_call_open(conn, call_ID,call_callback, phonenr,window);
224            /* Read and store the associated pids */
225            read(s, &lci->pid[0], sizeof(lci->pid[0]));
226            read(s, &lci->pid[1], sizeof(lci->pid[1]));
227            /* associate the local information with the call */
228            pptp_call_closure_put(conn, call, (void *) lci);
229            /* The rest is done on callback. */
230            /* Keep alive; wait for close */
231            retval = vector_insert(call_list, s, call); assert(retval);
232            if (s > max_fd) max_fd = s;
233            FD_SET(s, &call_set);
234            first = 0;
235        }
236skip_accept: /* Step 5c: Handle socket close */
237        for (i = 0; i < max_fd + 1; i++)
238            if (FD_ISSET(i, &read_set)) {
239                /* close it */
240                PPTP_CALL * call;
241                retval = vector_search(call_list, i, &call);
242                if (retval) {
243                    struct local_callinfo *lci =
244                        pptp_call_closure_get(conn, call);
245                    log("Closing connection (unhandled)");
246                    //if(lci->pid[0] > 1) kill(lci->pid[0], SIGTERM);
247                    //if(lci->pid[1] > 1) kill(lci->pid[1], SIGTERM);
248                    free(lci);
249                    /* soft shutdown.  Callback will do hard shutdown later */
250                    pptp_call_close(conn, call);
251                    vector_remove(call_list, i);
252                }
253                FD_CLR(i, &call_set);
254                close(i);
255            }
256    } while (vector_size(call_list) > 0 || first);
257shutdown:
258    {
259        int rc;
260        fd_set read_set, write_set;
261        struct timeval tv;
262	signal(SIGINT, callmgr_do_nothing);
263	signal(SIGTERM, callmgr_do_nothing);
264        /* warn("Shutdown"); */
265        /* kill all open calls */
266        for (i = 0; i < vector_size(call_list); i++) {
267            PPTP_CALL *call = vector_get_Nth(call_list, i);
268            //struct local_callinfo *lci = pptp_call_closure_get(conn, call);
269            log("Closing connection (shutdown)");
270            pptp_call_close(conn, call);
271            //if(lci->pid[0] > 1) kill(lci->pid[0], SIGTERM);
272            //if(lci->pid[1] > 1) kill(lci->pid[1], SIGTERM);
273        }
274        /* attempt to dispatch these messages */
275        FD_ZERO(&read_set);
276        FD_ZERO(&write_set);
277        pptp_fd_set(conn, &read_set, &write_set, &max_fd);
278	tv.tv_sec = 0;
279	tv.tv_usec = 0;
280	select(max_fd + 1, &read_set, &write_set, NULL, &tv);
281        rc = pptp_dispatch(conn, &read_set, &write_set);
282	if (rc > 0) {
283	  /* wait for a respond, a timeout because there might not be one */
284	  FD_ZERO(&read_set);
285	  FD_ZERO(&write_set);
286	  pptp_fd_set(conn, &read_set, &write_set, &max_fd);
287	  tv.tv_sec = 2;
288	  tv.tv_usec = 0;
289	  select(max_fd + 1, &read_set, &write_set, NULL, &tv);
290	  rc = pptp_dispatch(conn, &read_set, &write_set);
291	  if (rc > 0) {
292	    if (i > 0) sleep(2);
293	    /* no more open calls.  Close the connection. */
294	    pptp_conn_close(conn, PPTP_STOP_LOCAL_SHUTDOWN);
295	    /* wait for a respond, a timeout because there might not be one */
296	    FD_ZERO(&read_set);
297	    FD_ZERO(&write_set);
298	    pptp_fd_set(conn, &read_set, &write_set, &max_fd);
299	    tv.tv_sec = 2;
300	    tv.tv_usec = 0;
301	    select(max_fd + 1, &read_set, &write_set, NULL, &tv);
302	    pptp_dispatch(conn, &read_set, &write_set);
303	    if (rc > 0) sleep(2);
304	  }
305	}
306        /* with extreme prejudice */
307        pptp_conn_destroy(conn);
308        vector_destroy(call_list);
309    }
310cleanup:
311    signal(SIGINT, callmgr_do_nothing);
312    signal(SIGTERM, callmgr_do_nothing);
313    close_inetsock(inet_sock, inetaddr);
314    close_unixsock(unix_sock, inetaddr);
315    return 0;
316}
317
318/*** open_inetsock ************************************************************/
319int open_inetsock(struct in_addr inetaddr)
320{
321    struct sockaddr_in dest, src;
322    int s;
323    dest.sin_family = AF_INET;
324    dest.sin_port   = htons(PPTP_PORT);
325    dest.sin_addr   = inetaddr;
326    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
327        warn("socket: %s", strerror(errno));
328        return s;
329    }
330    if (localbind.s_addr != INADDR_NONE) {
331        bzero(&src, sizeof(src));
332        src.sin_family = AF_INET;
333        src.sin_addr   = localbind;
334        if (bind(s, (struct sockaddr *) &src, sizeof(src)) != 0) {
335            warn("bind: %s", strerror(errno));
336            close(s); return -1;
337        }
338    }
339    if (connect(s, (struct sockaddr *) &dest, sizeof(dest)) < 0) {
340        warn("connect: %s", strerror(errno));
341        close(s); return -1;
342    }
343    return s;
344}
345
346/*** open_unixsock ************************************************************/
347int open_unixsock(struct in_addr inetaddr)
348{
349    struct sockaddr_un where;
350    struct stat st;
351    char *dir;
352    int s;
353    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
354        warn("socket: %s", strerror(errno));
355        return s;
356    }
357    callmgr_name_unixsock( &where, inetaddr, localbind);
358    if (stat(where.sun_path, &st) >= 0)
359    {
360        warn("Call manager for %s is already running.", inet_ntoa(inetaddr));
361        close(s); return -1;
362    }
363   /* Make sure path is valid. */
364    dir = dirnamex(where.sun_path);
365    if (!make_valid_path(dir, 0770))
366        fatal("Could not make path to %s: %s", where.sun_path, strerror(errno));
367    free(dir);
368    if (bind(s, (struct sockaddr *) &where, sizeof(where)) < 0) {
369        warn("bind: %s", strerror(errno));
370        close(s); return -1;
371    }
372    chmod(where.sun_path, 0777);
373    listen(s, 127);
374    return s;
375}
376
377/*** close_inetsock ***********************************************************/
378void close_inetsock(int fd, struct in_addr inetaddr)
379{
380    close(fd);
381}
382
383/*** close_unixsock ***********************************************************/
384void close_unixsock(int fd, struct in_addr inetaddr)
385{
386    struct sockaddr_un where;
387    close(fd);
388    callmgr_name_unixsock(&where, inetaddr, localbind);
389    unlink(where.sun_path);
390}
391
392/*** make a unix socket address ***********************************************/
393void callmgr_name_unixsock(struct sockaddr_un *where,
394			   struct in_addr inetaddr,
395			   struct in_addr localbind)
396{
397    char localaddr[16], remoteaddr[16];
398    where->sun_family = AF_UNIX;
399    strncpy(localaddr,  inet_ntoa(localbind), 16);
400    strncpy(remoteaddr, inet_ntoa(inetaddr),  16);
401    snprintf(where->sun_path, sizeof(where->sun_path),
402            PPTP_SOCKET_PREFIX "%s:%i", remoteaddr,call_ID);
403}
404