#if HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include "pptpd.h" #define MFDSET(m,fd,fds) \ do { if( (fd) >= 0 ) { FD_SET((fd),(fds)); m= m < (fd) ? (fd) : (m) ; } } while (0) int loop( void ) { int m, i = 1; struct control_struct *control = NULL,*c,**cc; struct ppp_struct *p,**pp; fd_set rds,wrs; struct timeval ntv; struct timeval tv; int s,a; int salen; struct sockaddr_in sa; int istimeout; if( (s=socket(PF_INET,SOCK_STREAM,0))<0 ) return(-1); sa.sin_family = AF_INET; sa.sin_addr.s_addr=INADDR_ANY; sa.sin_port=htons(PPTP_PORT); setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)); if( bind(s,(struct sockaddr*)&sa,sizeof(struct sockaddr_in))<0 ) { close(s); return(-2); } listen(s, 8); gettimeofday(&ntv,NULL); tv=ntv; signal(SIGCHLD, SIG_IGN); for(;;) { FD_ZERO(&rds); FD_ZERO(&wrs); m=s; FD_SET(s,&rds); istimeout=0; for(c=control;c!=NULL;c=c->next) { MFDSET(m,c->ctrl_fd,&rds); MFDSET(m,c->gre_fd,&rds); for(p=c->ppp;p!=NULL;p=p->next) MFDSET(m,p->fd,&rds); if( !istimeout ) tv=c->gre_tv; tv=TV_MIN(tv,c->gre_tv); istimeout=1; } gettimeofday(&ntv,NULL); if( !istimeout ) { select(m+1,&rds,&wrs,NULL,NULL); gettimeofday(&ntv,NULL); } else if( !TV_IS_MIN(tv,ntv) ) { TV_SUB(tv,ntv); select(m+1,&rds,&wrs,NULL,&tv); gettimeofday(&ntv,NULL); } else { FD_ZERO(&rds); FD_ZERO(&wrs); } if( FD_ISSET(s,&rds) ) { salen=sizeof(struct sockaddr_in); if( (a=accept(s,(struct sockaddr*)&sa,&salen))>=0 ) { if( (c=init_control_struct(&control))==NULL ) { close(a); LOG("Can't init control struct"); } else { c->ctrl_fd=a; memcpy(&(c->addr_remote),&sa,sizeof(struct sockaddr_in)); getsockname(a,(struct sockaddr*)&sa,&salen); memcpy(&(c->addr_local),&sa,sizeof(struct sockaddr_in)); } } } for(cc=&control;(*cc)!=NULL;) { c=*cc; if( TV_IS_MIN(c->gre_tv,ntv) ) { gre_timeout(c); c->gre_tv=ntv; TV_ADD((c->gre_tv),(c->gre_dtv)); } if( c->ctrl_fd>=0 && FD_ISSET(c->ctrl_fd,&rds) ) { if( read_control_packet(c)<0 ) { finish_control_struct(c); continue; } } if( c->gre_fd >= 0 && FD_ISSET(c->gre_fd,&rds) ) { if( read_gre_packet(c)<0 ) { finish_control_struct(c); continue; } } for(pp=&(c->ppp);*pp!=NULL;) { if( (*pp)->fd>=0 && FD_ISSET((*pp)->fd,&rds) ) if( read_ppp_packet(c,(*pp))<0 ) { void * close_packet = prepare_call_close_packet(* pp, LOST_CARRIER); if (close_packet) { send_packet(c, close_packet); free(close_packet); } unlink_and_release_ppp(&pp,(*pp)->call_id); if (*pp == NULL) break; } if ((*pp)->next == NULL) break; pp=&((*pp)->next); } if ((*cc)->next == NULL) break; cc=&((*cc)->next); } } } int main( int argc, char *argv[] ) { char *p; int i; if( (p=strrchr(argv[0],'/'))!=NULL ) p++; else p=argv[0]; while ((i=getopt(argc, argv, "vhc:")) != EOF) switch (i) { case '?': fprintf(stderr, "%s: Unknown option, try -h.\n", p); return 1; case ':': fprintf(stderr, "%s: Missing argument, try -h.\n", p); return 1; case 'v': puts("Version " VERSION); return 0; case 'h': printf("%s: Usage: \n" "\t%s -h ... this help text\n" "\t%s -v ... current version\n" "\t%s [-c ] ... start, configure from that file instead of default\n", p, argv[0], argv[0], argv[0]); return 0; } printf("Configured %d pppd cmdlines\n",conf_ppp(PPPD_CMDLINESFILE)); openlog(p,LOG_PID,LOG_DAEMON); LOG("started"); return(loop()); }