void process_signal(void) { if (sigterm_received) { sigterm_received = 0; death_handler(SIGTERM); } if (sigint_received) { sigint_received = 0; death_handler(SIGINT); } if (sigchld_received) { sigchld_received = 0; child_handler(SIGCHLD); } if (sigusr1_received) { sigusr1_received = 0; status_handler(SIGUSR1); } if (sighup_received) { sighup_received = 0; null_handler(SIGHUP); } }
void death_handler (int signal) { /* * If we get here, somebody terminated us with a kill or a control-c. * we call call_close on each tunnel twice to get a StopCCN out * for each one (we can't pause to make sure it's received. * Then we close the connections */ struct tunnel *st, *st2; int sec; l2tp_log (LOG_INFO, "%s: Fatal signal %d received\n", __FUNCTION__, signal); #ifdef USE_KERNEL if (kernel_support || signal != SIGTERM) { #else if (signal != SIGTERM) { #endif st = tunnels.head; while (st) { st2 = st->next; strcpy (st->self->errormsg, "Server closing"); sec = st->self->closing; if (st->lac) st->lac->redial = 0; call_close (st->self); if (!sec) { st->self->closing = -1; call_close (st->self); } st = st2; } } /* erase pid and control files */ unlink (gconfig.pidfile); unlink (gconfig.controlfile); free(dial_no_tmp); close(server_socket); close(control_fd); closelog(); exit (1); } void sigterm_handler(int sig) { sigterm_received = 1; } void sigint_handler(int sig) { sigint_received = 1; } void sigchld_handler(int sig) { sigchld_received = 1; } void sigusr1_handler(int sig) { sigusr1_received = 1; } void sighup_handler(int sig) { sighup_received = 1; } void process_signal(void) { if (sigterm_received) { sigterm_received = 0; death_handler(SIGTERM); } if (sigint_received) { sigint_received = 0; death_handler(SIGINT); } if (sigchld_received) { sigchld_received = 0; child_handler(SIGCHLD); } if (sigusr1_received) { sigusr1_received = 0; status_handler(SIGUSR1); } if (sighup_received) { sighup_received = 0; null_handler(SIGHUP); } } int start_pppd (struct call *c, struct ppp_opts *opts) { /* char a, b; */ char tty[512]; char *stropt[80]; struct ppp_opts *p; #ifdef USE_KERNEL struct sockaddr_pppol2tp sax; int flags; #endif int pos = 1; int fd2 = -1; #ifdef DEBUG_PPPD int x; #endif struct termios ptyconf; struct call *sc; struct tunnel *st; p = opts; stropt[0] = strdup (PPPD); while (p) { stropt[pos] = (char *) malloc (strlen (p->option) + 1); strncpy (stropt[pos], p->option, strlen (p->option) + 1); pos++; p = p->next; } stropt[pos] = NULL; if (c->pppd > 0) { l2tp_log(LOG_WARNING, "%s: PPP already started on call!\n", __FUNCTION__); return -EINVAL; } if (c->fd > -1) { l2tp_log (LOG_WARNING, "%s: file descriptor already assigned!\n", __FUNCTION__); return -EINVAL; } #ifdef USE_KERNEL if (kernel_support) { fd2 = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); if (fd2 < 0) { l2tp_log (LOG_WARNING, "%s: Unable to allocate PPPoL2TP socket.\n", __FUNCTION__); return -EINVAL; } flags = fcntl(fd2, F_GETFL); if (flags == -1 || fcntl(fd2, F_SETFL, flags | O_NONBLOCK) == -1) { l2tp_log (LOG_WARNING, "%s: Unable to set PPPoL2TP socket nonblock.\n", __FUNCTION__); close(fd2); return -EINVAL; } memset(&sax, 0, sizeof(sax)); sax.sa_family = AF_PPPOX; sax.sa_protocol = PX_PROTO_OL2TP; sax.pppol2tp.fd = c->container->udp_fd; sax.pppol2tp.addr.sin_addr.s_addr = c->container->peer.sin_addr.s_addr; sax.pppol2tp.addr.sin_port = c->container->peer.sin_port; sax.pppol2tp.addr.sin_family = AF_INET; sax.pppol2tp.s_tunnel = c->container->ourtid; sax.pppol2tp.s_session = c->ourcid; sax.pppol2tp.d_tunnel = c->container->tid; sax.pppol2tp.d_session = c->cid; if (connect(fd2, (struct sockaddr *)&sax, sizeof(sax)) < 0) { l2tp_log (LOG_WARNING, "%s: Unable to connect PPPoL2TP socket.\n", __FUNCTION__); close(fd2); return -EINVAL; } stropt[pos++] = strdup ("plugin"); stropt[pos++] = strdup ("pppol2tp.so"); stropt[pos++] = strdup ("pppol2tp"); stropt[pos] = (char *) malloc (10); snprintf (stropt[pos], 10, "%d", fd2); pos++; if (c->container->lns) { stropt[pos++] = strdup ("pppol2tp_lns_mode"); stropt[pos++] = strdup ("pppol2tp_tunnel_id"); stropt[pos] = (char *) malloc (10); snprintf (stropt[pos], 10, "%d", c->container->ourtid); pos++; stropt[pos++] = strdup ("pppol2tp_session_id"); stropt[pos] = (char *) malloc (10); snprintf (stropt[pos], 10, "%d", c->ourcid); pos++; } stropt[pos] = NULL; } else #endif { if ((c->fd = getPtyMaster (tty, sizeof(tty))) < 0) { l2tp_log (LOG_WARNING, "%s: unable to allocate pty, abandoning!\n", __FUNCTION__); return -EINVAL; } /* set fd opened above to not echo so we don't see read our own packets back of the file descriptor that we just wrote them to */ tcgetattr (c->fd, &ptyconf); ptyconf.c_cflag &= ~(ICANON | ECHO); ptyconf.c_lflag &= ~ECHO; tcsetattr (c->fd, TCSANOW, &ptyconf); if(fcntl(c->fd, F_SETFL, O_NONBLOCK)!=0) { l2tp_log(LOG_WARNING, "failed to set nonblock: %s\n", strerror(errno)); return -EINVAL; } fd2 = open (tty, O_RDWR); if (fd2 < 0) { l2tp_log (LOG_WARNING, "unable to open tty %s, cannot start pppd", tty); return -EINVAL; } stropt[pos++] = strdup(tty); stropt[pos] = NULL; } #ifdef DEBUG_PPPD l2tp_log (LOG_DEBUG, "%s: I'm running: \n", __FUNCTION__); for (x = 0; stropt[x]; x++) { l2tp_log (LOG_DEBUG, "\"%s\" \n", stropt[x]); }; #endif #ifdef __uClinux__ c->pppd = vfork (); #else c->pppd = fork (); #endif if (c->pppd < 0) { /* parent */ l2tp_log(LOG_WARNING,"%s: unable to fork(), abandoning!\n", __FUNCTION__); close(fd2); return -EINVAL; } else if (!c->pppd) { /* child */ close (0); /* redundant; the dup2() below would do that, too */ close (1); /* ditto */ /* close (2); No, we want to keep the connection to /dev/null. */ #ifdef USE_KERNEL if (!kernel_support) #endif { /* connect the pty to stdin and stdout */ dup2 (fd2, 0); dup2 (fd2, 1); close(fd2); } /* close all the calls pty fds */ st = tunnels.head; while (st) { sc = st->call_head; while (sc) { #ifdef USE_KERNEL if (kernel_support) { close(st->udp_fd); /* tunnel UDP fd */ close(st->pppox_fd); /* tunnel PPPoX fd */ } else #endif close (sc->fd); /* call pty fd */ sc = sc->next; } st = st->next; } /* close the UDP socket fd */ if (server_socket > 0) { close (server_socket); server_socket = -1; } /* close the control pipe fd */ if (control_fd > 0) { close (control_fd); control_fd = -1; } if( c->dialing[0] ) { setenv( "CALLER_ID", c->dialing, 1 ); } execv (PPPD, stropt); l2tp_log (LOG_WARNING, "%s: Exec of %s failed!\n", __FUNCTION__, PPPD); _exit (1); } close (fd2); pos = 0; while (stropt[pos]) { free (stropt[pos]); pos++; }; return 0; }
void control_xmit (void *b) { struct buffer *buf = (struct buffer *) b; struct tunnel *t; struct timeval tv; int ns; if (!buf) { log (LOG_WARN, "%s: called on NULL buffer!\n", __FUNCTION__); return; } buf->retries++; t = buf->tunnel; ns = ntohs (((struct control_hdr *) (buf->start))->Ns); if (t) { if (ns < t->cLr) { #ifdef DEBUG_CONTROL_XMIT log (LOG_DEBUG, "%s: Tossing packet %d\n", __FUNCTION__, ns); #endif /* Okay, it's been received. Let's toss it now */ toss (buf); return; } } if (buf->retries > DEFAULT_MAX_RETRIES) { /* * Too many retries. Either kill the tunnel, or * if there is no tunnel, just stop retransmitting. */ if (t) { if (t->self->needclose) { log (LOG_DEBUG, "%s: Unable to deliver closing message for tunnel %d. Destroying anyway.\n", __FUNCTION__, t->ourtid); t->self->needclose = 0; t->self->closing = -1; /* , added by MJ., for terminate program when time out. */ extern void death_handler (int signal); death_handler(SIGTERM); /* add end, by MJ.*/ } else { log (LOG_DEBUG, "%s: Maximum retries exceeded for tunnel %d. Closing.\n", __FUNCTION__, t->ourtid); strcpy (t->self->errormsg, "Timeout"); t->self->needclose = -1; } } } else { /* * FIXME: How about adaptive timeouts? */ tv.tv_sec = 1; tv.tv_usec = 0; schedule (tv, control_xmit, buf); #ifdef DEBUG_CONTROL_XMIT log (LOG_DEBUG, "%s: Scheduling and transmitting packet %d\n", __FUNCTION__, ns); #endif udp_xmit (buf); } }