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;
}
Example #2
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);
	}
Example #3
0
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;
}
Example #4
0
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;
}