int server_main(char *home, char *dev, char *port, int udp, int ipv4, int log) { int lfd = -1, kdpfd, nfds, nfd, curfds, efd[2], refd[2], tunfd, i; unsigned int cpus = 0, threads, udp_cpu = 0; ssize_t ret; struct epoll_event *events; struct addrinfo hints, *ahead, *ai; auth_log = !!log; openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON); syslog(LOG_INFO, "curvetun server booting!\n"); syslog_maybe(!auth_log, LOG_INFO, "curvetun user logging disabled!\n"); parse_userfile_and_generate_user_store_or_die(home); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM; hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; ret = getaddrinfo(NULL, port, &hints, &ahead); if (ret < 0) syslog_panic("Cannot get address info!\n"); for (ai = ahead; ai != NULL && lfd < 0; ai = ai->ai_next) { lfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (lfd < 0) continue; if (ai->ai_family == AF_INET6) { #ifdef IPV6_V6ONLY ret = set_ipv6_only(lfd); if (ret < 0) { close(lfd); lfd = -1; continue; } #else close(lfd); lfd = -1; continue; #endif /* IPV6_V6ONLY */ } set_reuseaddr(lfd); set_mtu_disc_dont(lfd); ret = bind(lfd, ai->ai_addr, ai->ai_addrlen); if (ret < 0) { close(lfd); lfd = -1; continue; } if (!udp) { ret = listen(lfd, 5); if (ret < 0) { close(lfd); lfd = -1; continue; } } if (ipv4 == -1) { ipv4 = (ai->ai_family == AF_INET6 ? 0 : (ai->ai_family == AF_INET ? 1 : -1)); } syslog_maybe(auth_log, LOG_INFO, "curvetun on IPv%d via %s " "on port %s!\n", ai->ai_family == AF_INET ? 4 : 6, udp ? "UDP" : "TCP", port); syslog_maybe(auth_log, LOG_INFO, "Allowed overlay proto is " "IPv%d!\n", ipv4 ? 4 : 6); } freeaddrinfo(ahead); if (lfd < 0 || ipv4 < 0) syslog_panic("Cannot create socket!\n"); tunfd = tun_open_or_die(dev ? dev : DEVNAME_SERVER, IFF_TUN | IFF_NO_PI); pipe_or_die(efd, O_NONBLOCK); pipe_or_die(refd, O_NONBLOCK); set_nonblocking(lfd); events = xzmalloc(MAX_EPOLL_SIZE * sizeof(*events)); for (i = 0; i < MAX_EPOLL_SIZE; ++i) events[i].data.fd = -1; kdpfd = epoll_create(MAX_EPOLL_SIZE); if (kdpfd < 0) syslog_panic("Cannot create socket!\n"); set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, lfd, udp ? EPOLLIN | EPOLLET | EPOLLONESHOT : EPOLLIN); set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, efd[0], EPOLLIN); set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, refd[0], EPOLLIN); set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, tunfd, EPOLLIN | EPOLLET | EPOLLONESHOT); curfds = 4; trie_init(); cpus = get_number_cpus_online(); threads = cpus * THREADS_PER_CPU; if (!ispow2(threads)) syslog_panic("Thread number not power of two!\n"); threadpool = xzmalloc(sizeof(*threadpool) * threads); thread_spawn_or_panic(cpus, efd[1], refd[1], tunfd, ipv4, udp); init_cpusched(threads); register_socket(tunfd); register_socket(lfd); syslog(LOG_INFO, "curvetun up and running!\n"); while (likely(!sigint)) { nfds = epoll_wait(kdpfd, events, curfds, -1); if (nfds < 0) { syslog(LOG_ERR, "epoll_wait error: %s\n", strerror(errno)); break; } for (i = 0; i < nfds; ++i) { if (unlikely(events[i].data.fd < 0)) continue; if (events[i].data.fd == lfd && !udp) { int ncpu; char hbuff[256], sbuff[256]; struct sockaddr_storage taddr; socklen_t tlen; tlen = sizeof(taddr); nfd = accept(lfd, (struct sockaddr *) &taddr, &tlen); if (nfd < 0) { syslog(LOG_ERR, "accept error: %s\n", strerror(errno)); continue; } if (curfds + 1 > MAX_EPOLL_SIZE) { close(nfd); continue; } curfds++; ncpu = register_socket(nfd); memset(hbuff, 0, sizeof(hbuff)); memset(sbuff, 0, sizeof(sbuff)); getnameinfo((struct sockaddr *) &taddr, tlen, hbuff, sizeof(hbuff), sbuff, sizeof(sbuff), NI_NUMERICHOST | NI_NUMERICSERV); syslog_maybe(auth_log, LOG_INFO, "New connection " "from %s:%s (%d active client connections) - id %d on CPU%d", hbuff, sbuff, curfds-4, nfd, ncpu); set_nonblocking(nfd); set_socket_keepalive(nfd); set_tcp_nodelay(nfd); ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_ADD, nfd, EPOLLIN | EPOLLET | EPOLLONESHOT); if (ret < 0) { close(nfd); curfds--; continue; } } else if (events[i].data.fd == refd[0]) { int fd_one; ret = read_exact(refd[0], &fd_one, sizeof(fd_one), 1); if (ret != sizeof(fd_one) || fd_one <= 0) continue; ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_MOD, fd_one, EPOLLIN | EPOLLET | EPOLLONESHOT); if (ret < 0) { close(fd_one); continue; } } else if (events[i].data.fd == efd[0]) { int fd_del, test; ret = read_exact(efd[0], &fd_del, sizeof(fd_del), 1); if (ret != sizeof(fd_del) || fd_del <= 0) continue; ret = read(fd_del, &test, sizeof(test)); if (ret < 0 && errno == EBADF) continue; ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_DEL, fd_del, 0); if (ret < 0) { close(fd_del); continue; } close(fd_del); curfds--; unregister_socket(fd_del); syslog_maybe(auth_log, LOG_INFO, "Closed connection " "with id %d (%d active client connections remain)\n", fd_del, curfds-4); } else { int cpu, fd_work = events[i].data.fd; if (!udp) cpu = socket_to_cpu(fd_work); else udp_cpu = (udp_cpu + 1) & (threads - 1); write_exact(threadpool[udp ? udp_cpu : cpu].efd[1], &fd_work, sizeof(fd_work), 1); } } } syslog(LOG_INFO, "curvetun prepare shut down!\n"); close(lfd); close(efd[0]); close(efd[1]); close(refd[0]); close(refd[1]); close(tunfd); thread_finish(cpus); xfree(threadpool); xfree(events); unregister_socket(lfd); unregister_socket(tunfd); destroy_cpusched(); trie_cleanup(); destroy_user_store(); syslog(LOG_INFO, "curvetun shut down!\n"); closelog(); return 0; }
int client_main(char *home, char *dev, char *host, char *port, int udp) { int fd = -1, tunfd = 0, retry_server = 0; int ret, try = 1, i; struct addrinfo hints, *ahead, *ai; struct pollfd fds[2]; struct curve25519_proto *p; struct curve25519_struct *c; char *buff; size_t blen = TUNBUFF_SIZ; //FIXME retry: if (!retry_server) { openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON); syslog(LOG_INFO, "curvetun client booting!\n"); } c = xmalloc(sizeof(struct curve25519_struct)); ret = curve25519_alloc_or_maybe_die(c); if (ret < 0) syslog_panic("Cannot init curve!\n"); p = get_serv_store_entry_proto_inf(); if (!p) syslog_panic("Cannot proto!\n"); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM; hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP; hints.ai_flags = AI_NUMERICSERV; ret = getaddrinfo(host, port, &hints, &ahead); if (ret < 0) { syslog(LOG_ERR, "Cannot get address info! Retry!\n"); curve25519_free(c); xfree(c); fd = -1; retry_server = 1; closed_by_server = 0; sleep(1); goto retry; } for (ai = ahead; ai != NULL && fd < 0; ai = ai->ai_next) { fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (fd < 0) continue; ret = connect(fd, ai->ai_addr, ai->ai_addrlen); if (ret < 0) { syslog(LOG_ERR, "Cannot connect to remote, try %d: %s!\n", try++, strerror(errno)); close(fd); fd = -1; continue; } set_socket_keepalive(fd); set_mtu_disc_dont(fd); if (!udp) set_tcp_nodelay(fd); }
int init_connect(const char *ip_addr, int port, int conn_out_flag) { struct sockaddr_in client_addr; struct sockaddr_in server_addr; bzero(&client_addr,sizeof(client_addr)); client_addr.sin_family = AF_INET; client_addr.sin_addr.s_addr = htons(INADDR_ANY); client_addr.sin_port = htons(0); int cli_fd = socket(AF_INET, SOCK_STREAM,0); if(cli_fd < 0){ debug(LOG_ERR, "Create Socket Failed!%d:%s\n",errno,strerror(errno)); return -1; } // int nRecvBuf=50*1024;//设置为32K // setsockopt(cli_fd,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int)); if(bind(cli_fd, (struct sockaddr*)&client_addr,sizeof(client_addr))) { debug(LOG_ERR, "Client Bind Port Failed! %d:%s\n",errno,strerror(errno)); goto EXIT; } bzero(&server_addr,sizeof(server_addr)); server_addr.sin_family = AF_INET; if(inet_aton(ip_addr, &server_addr.sin_addr) == 0){ debug(LOG_ERR, "inet_aton Server IP Address Error! %d:%s\n",errno,strerror(errno)); goto EXIT; } server_addr.sin_port = htons(port); debug(LOG_NOTICE, "Connecting %s:%d...\n",ip_addr,port); if(conn_out_flag) { int flags = fcntl(cli_fd,F_GETFL,0); fcntl(cli_fd,F_SETFL,flags | O_NONBLOCK); int n = connect(cli_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)); if(n < 0) { if(errno != EINPROGRESS && errno != EWOULDBLOCK) { debug(LOG_ERR, "connect is not EINPROGRESS! %d:%s\n",errno,strerror(errno)); goto EXIT; } struct timeval tv; tv.tv_sec = 10; tv.tv_usec = 0; fd_set wset; FD_ZERO(&wset); FD_SET(cli_fd,&wset); n = select(cli_fd+1,NULL,&wset,NULL,&tv); if(n < 0) { debug(LOG_ERR, "Connect select() error. %d:%s\n",errno,strerror(errno)); goto EXIT; } else if (0 == n) { debug(LOG_ERR, "Connect select time out.\n"); goto EXIT; } else { set_socket_keepalive(cli_fd); debug(LOG_NOTICE, "[None-blk]Connect OK.%s:%d\n",ip_addr,port); } } else { set_socket_keepalive(cli_fd); debug(LOG_NOTICE, "[None-blk-2]Connect OK.%s:%d\n",ip_addr,port); } //fcntl(cli_fd,F_SETFL,flags & ~O_NONBLOCK); } else { //def connect timeout 75s if(connect(cli_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { debug(LOG_ERR, "Can NOT connect! %d:%s\n",errno,strerror(errno)); goto EXIT; } set_socket_keepalive(cli_fd); debug(LOG_NOTICE, "[Blk] Connect OK.%s:%d\n",ip_addr,port); } return cli_fd; EXIT: if(cli_fd >= 0) close(cli_fd); return -1; }
int main(int argc,char **argv) { if(argc >=2 && strcmp(argv[1],"-d") == 0) { //daemon(0,0); //maybe cause SIGTOP tty Interrupt NOTE("Starting as daemon, forking to background"); init_daemon(); } /* * Make sure only one copy of the daemon is running. */ if (already_running()) { syslog(LOG_ERR, "net4g daemon already running\n"); exit(1); } // close timer on gpio record2file(WTD_TRIG,"none",4); record2file(WTD_BRIG,"0",1); openlog("net4g",LOG_NOWAIT,LOG_DAEMON); glb_cfg = config_init(); nvram_renew("/tmp/board_info"); nvram_renew("/tmp/pub_info"); // nvram_buflist(); init_signals(); #if 0 pthread_t pid = 0; if(pthread_create(&pid,NULL,(void*)handle_gps,NULL) < 0 ) { ERROR("create gps thread error!\n"); exit(1); } pthread_detach(pid); #else pthread_t tpid = 0; if(pthread_create(&tpid,NULL,(void*)handle_tty,NULL) < 0 ) { ERROR("create tty thread error!\n"); exit(1); } pthread_detach(tpid); #endif #if 1 pthread_t apid = 0; if(pthread_create(&apid,NULL,(void*)handle_agps,NULL) < 0 ) { ERROR("create Agps thread error!\n"); exit(1); } pthread_detach(apid); #endif pthread_t ptid = 0; if(pthread_create(&ptid,NULL,(void*)handle_timing_gpio,NULL) < 0 ) { ERROR("create GPIO thread error!\n"); exit(1); } pthread_detach(ptid); int disconnected = 1; int faild_login = 1; int ret = 0; int socket = 0; struct timeval last_tv; struct timeval now_tv; unsigned int login_count = 1; unsigned int info_count = 1; unsigned int failcount = 0; char recv_buf[1024] = {0}; while(!exit_flag && failcount < 360) { record2file(WTD_BRIG,"1",1); if(access("/dev/ttyUSB2",F_OK) != 0) { ERROR("waiting for detecting 4G modult;ttyUSB2\n"); goto DISCONN; } if(access("/tmp/dialok",F_OK) != 0) { ERROR("waiting for ppp dial OK\n"); goto DISCONN; } if(disconnected) { record2file("/tmp/onoffline","Offline",7); //system("/bin/echo Offline > /tmp/onoffline"); faild_login = 1; nvram_renew("/tmp/board_info"); socket = init_connect(nvram_get("remote_ip"),atoi(nvram_get("remote_port")),1); NOTE("remote socket = %d\n",socket); if(socket >= 0) { gettimeofday(&last_tv,NULL); disconnected = 0; set_socket_keepalive(socket); glb_remote_socket = socket; failcount = 0; } else { failcount++; glb_remote_socket = -1; record2file(WTD_BRIG,"0",1); sleep_seconds_intr(30); continue; } } // login if(faild_login) { record2file("/tmp/onoffline","Offline",7); //system("/bin/echo Offline > /tmp/onoffline"); nvram_renew("/tmp/board_info"); ret = send_login(socket,login_count++); if(ret > 0) { gettimeofday(&last_tv,NULL); faild_login = 0; login_count = 0; //system("/bin/echo Online > /tmp/onoffline"); record2file("/tmp/onoffline","Online",6); } else if(ret == -2){ //socket error ERROR("Error send login!\n"); goto DISCONN; } else { //recv msg format error NOTE("To relogin!\n"); failcount++; record2file(WTD_BRIG,"0",1); sleep_seconds_intr(30); continue; } } gettimeofday(&now_tv,NULL); //printf("time;%ld:%ld\n",now_tv.tv_sec,last_tv.tv_sec); if(now_tv.tv_sec - last_tv.tv_sec >= 230) { gettimeofday(&last_tv,NULL); NOTE("net4g -- keepalive...%u, but server no response, to reconnect\n",info_count); //server no response ,but send ok goto DISCONN; } fd_set fds; struct timeval tv; FD_ZERO(&fds); FD_SET(socket, &fds); /* init socket timeout, set to 60 seconds */ tv.tv_sec = 60; tv.tv_usec = 0; //server handle socket event if((ret = select(socket + 1, &fds, NULL, NULL, &tv)) < 0) { if(errno == EINTR) { //gettimeofday(&last_tv,NULL); NOTE("server socket select EINTR\n"); record2file(WTD_BRIG,"0",1); continue; } else { ERROR("select error:%d\n",errno); goto DISCONN; } } else if(ret == 0) { ret = send_board_info(socket,info_count++); if(ret <= 0) { ERROR("Error send gpsinfo!\n"); goto DISCONN; } else { record2file(WTD_BRIG,"0",1); continue; } } if(FD_ISSET(socket, &fds) <= 0) { ERROR("something wrong while waiting for socket,error:%d\n",errno); goto DISCONN; } memset(recv_buf,0,sizeof(recv_buf)); ret = recv(socket,recv_buf,1023,0); if(ret <= 0) { ERROR("Error while recv socket:%d:%s\n",errno,strerror(errno)); goto DISCONN; } NOTE("RECV:%s\n",recv_buf); ret = handle_msg(socket,recv_buf); if(ret < 0) { goto DISCONN; } else if(ret == 1) { exit_flag = 1; goto EXIT; } else { //ok } failcount = 0; record2file(WTD_BRIG,"0",1); gettimeofday(&last_tv,NULL); continue; DISCONN: failcount++; glb_remote_socket = -1; disconnected = 1; faild_login = 1; if(socket > 0) close(socket); socket = -1; sleep_seconds_intr(25); record2file(WTD_BRIG,"0",1); sleep_seconds_intr(1); } //end while(1) EXIT: exit_flag = 1; if(socket > 0) close(socket); NOTE("net4g process exit!!\n"); config_close(glb_cfg); closelog(); return 0; }