diff --git a/app/src/main/jni/netguard/netguard.c b/app/src/main/jni/netguard/netguard.c index f84802fa..4c838098 100644 --- a/app/src/main/jni/netguard/netguard.c +++ b/app/src/main/jni/netguard/netguard.c @@ -25,10 +25,9 @@ // Global variables JavaVM *jvm = NULL; +int pipefds[2]; pthread_t thread_id = 0; pthread_mutex_t lock; -jboolean stopping = 0; -jboolean signaled = 0; int loglevel = ANDROID_LOG_WARN; extern int max_tun_msg; @@ -108,6 +107,17 @@ Java_eu_faircode_netguard_ServiceSinkhole_jni_1init(JNIEnv *env, jobject instanc if (pthread_mutex_init(&lock, NULL)) log_android(ANDROID_LOG_ERROR, "pthread_mutex_init failed"); + + // Create signal pipe + if (pipe(pipefds)) + log_android(ANDROID_LOG_ERROR, "Create pipe error %d: %s", errno, strerror(errno)); + else + for (int i = 0; i < 2; i++) { + int flags = fcntl(pipefds[i], F_GETFL, 0); + if (flags < 0 || fcntl(pipefds[i], F_SETFL, flags | O_NONBLOCK) < 0) + log_android(ANDROID_LOG_ERROR, "fcntl pipefds[%d] O_NONBLOCK error %d: %s", + i, errno, strerror(errno)); + } } JNIEXPORT void JNICALL @@ -155,14 +165,12 @@ Java_eu_faircode_netguard_ServiceSinkhole_jni_1stop( pthread_t t = thread_id; log_android(ANDROID_LOG_WARN, "Stop tun %d thread %x", tun, t); if (t && pthread_kill(t, 0) == 0) { - stopping = 1; - log_android(ANDROID_LOG_WARN, "Kill thread %x", t); - int err = pthread_kill(t, SIGUSR1); - if (err != 0) - log_android(ANDROID_LOG_WARN, "pthread_kill error %d: %s", err, strerror(err)); + log_android(ANDROID_LOG_WARN, "Write pipe thread %x", t); + if (write(pipefds[1], "x", 1) < 0) + log_android(ANDROID_LOG_WARN, "Write pipe error %d: %s", errno, strerror(errno)); else { log_android(ANDROID_LOG_WARN, "Join thread %x", t); - err = pthread_join(t, NULL); + int err = pthread_join(t, NULL); if (err != 0) log_android(ANDROID_LOG_WARN, "pthread_join error %d: %s", err, strerror(err)); } @@ -295,6 +303,10 @@ Java_eu_faircode_netguard_ServiceSinkhole_jni_1done(JNIEnv *env, jobject instanc if (pthread_mutex_destroy(&lock)) log_android(ANDROID_LOG_ERROR, "pthread_mutex_destroy failed"); + + for (int i = 0; i < 2; i++) + if (close(pipefds[i])) + log_android(ANDROID_LOG_ERROR, "Close pipe error %d: %s", errno, strerror(errno)); } // JNI Util diff --git a/app/src/main/jni/netguard/session.c b/app/src/main/jni/netguard/session.c index eefb4e18..88346c27 100644 --- a/app/src/main/jni/netguard/session.c +++ b/app/src/main/jni/netguard/session.c @@ -20,10 +20,9 @@ #include "netguard.h" extern JavaVM *jvm; +extern int pipefds[2]; extern pthread_t thread_id; extern pthread_mutex_t lock; -extern jboolean stopping; -extern jboolean signaled; struct ng_session *ng_session = NULL; @@ -46,18 +45,9 @@ void clear() { ng_session = NULL; } -void handle_signal(int sig, siginfo_t *info, void *context) { - log_android(ANDROID_LOG_DEBUG, "Signal %d", sig); - signaled = 1; -} - void *handle_events(void *a) { - int sdk; int epoll_fd; struct timespec ts; - sigset_t blockset; - sigset_t emptyset; - struct sigaction sa; struct arguments *args = (struct arguments *) a; log_android(ANDROID_LOG_WARN, "Start events tun=%d thread %x", args->tun, thread_id); @@ -71,9 +61,7 @@ void *handle_events(void *a) { } args->env = env; - // Get SDK version - sdk = sdk_int(env); - + // Get max sessions int maxsessions = 1024; struct rlimit rlim; if (getrlimit(RLIMIT_NOFILE, &rlim)) @@ -84,22 +72,10 @@ void *handle_events(void *a) { rlim.rlim_cur, rlim.rlim_max, maxsessions); } - // Block SIGUSR1 - sigemptyset(&blockset); - sigaddset(&blockset, SIGUSR1); - sigprocmask(SIG_BLOCK, &blockset, NULL); - - /// Handle SIGUSR1 - sa.sa_sigaction = handle_signal; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sigaction(SIGUSR1, &sa, NULL); - // Terminate existing sessions not allowed anymore check_allowed(args); - stopping = 0; - signaled = 0; + int stopping = 0; // Open epoll fd epoll_fd = epoll_create(1); @@ -109,6 +85,17 @@ void *handle_events(void *a) { stopping = 1; } + // Monitor stop events + struct epoll_event ev_pipe; + memset(&ev_pipe, 0, sizeof(struct epoll_event)); + ev_pipe.events = EPOLLIN; + ev_pipe.data.ptr = &ev_pipe; + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pipefds[0], &ev_pipe)) { + log_android(ANDROID_LOG_ERROR, "epoll add pipe error %d: %s", errno, strerror(errno)); + report_exit(args, "epoll add pipe error %d: %s", errno, strerror(errno)); + stopping = 1; + } + // Monitor tun events struct epoll_event ev_tun; memset(&ev_tun, 0, sizeof(struct epoll_event)); @@ -120,8 +107,6 @@ void *handle_events(void *a) { stopping = 1; } - sigemptyset(&emptyset); - // Loop while (!stopping) { log_android(ANDROID_LOG_DEBUG, "Loop thread %x", thread_id); @@ -178,36 +163,24 @@ void *handle_events(void *a) { } } - // https://bugzilla.mozilla.org/show_bug.cgi?id=1093893 - int idle = (tsessions + usessions + tsessions == 0 && sdk >= 16); - log_android(ANDROID_LOG_DEBUG, "sessions ICMP %d UDP %d TCP %d max %d/%d idle %d sdk %d", - isessions, usessions, tsessions, sessions, maxsessions, idle, sdk); + log_android(ANDROID_LOG_DEBUG, "sessions ICMP %d UDP %d TCP %d max %d/%d", + isessions, usessions, tsessions, sessions, maxsessions); // Next event time - ts.tv_sec = (sdk < 16 ? 5 : get_select_timeout(sessions, maxsessions)); + ts.tv_sec = get_select_timeout(sessions, maxsessions); ts.tv_nsec = 0; // TODO: check if tun is writable? // Poll struct epoll_event ev; - sigset_t origmask; - pthread_sigmask(SIG_SETMASK, &emptyset, &origmask); int ready = epoll_wait(epoll_fd, &ev, 1, ts.tv_sec * 1000); - pthread_sigmask(SIG_SETMASK, &origmask, NULL); if (ready < 0) { if (errno == EINTR) { - if (stopping && signaled) { ; - log_android(ANDROID_LOG_WARN, - "epoll signaled tun %d thread %x", args->tun, thread_id); - report_exit(args, NULL); - break; - } else { - log_android(ANDROID_LOG_DEBUG, - "epoll interrupted tun %d thread %x", args->tun, thread_id); - continue; - } + log_android(ANDROID_LOG_DEBUG, + "epoll interrupted tun %d thread %x", args->tun, thread_id); + continue; } else { log_android(ANDROID_LOG_ERROR, "epoll tun %d thread %x error %d: %s", @@ -221,13 +194,23 @@ void *handle_events(void *a) { if (ready == 0) log_android(ANDROID_LOG_DEBUG, "epoll timeout"); else { - log_android(ANDROID_LOG_DEBUG, "epoll ready %d in %d out %d err %d prot %d sock %d", - ready, - (ev.events & EPOLLIN) != 0, - (ev.events & EPOLLOUT) != 0, - (ev.events & EPOLLERR) != 0, - (ev.data.ptr == NULL ? -1 : ((struct ng_session *) ev.data.ptr)->protocol), - (ev.data.ptr == NULL ? -1 : ((struct ng_session *) ev.data.ptr)->socket)); + if (ev.data.ptr != &ev_pipe) { + if (ev.data.ptr == NULL) + log_android(ANDROID_LOG_DEBUG, "epoll ready %d in %d out %d err %d", + ready, + (ev.events & EPOLLIN) != 0, + (ev.events & EPOLLOUT) != 0, + (ev.events & EPOLLERR) != 0); + else + log_android(ANDROID_LOG_DEBUG, + "epoll ready %d in %d out %d err %d prot %d sock %d", + ready, + (ev.events & EPOLLIN) != 0, + (ev.events & EPOLLOUT) != 0, + (ev.events & EPOLLERR) != 0, + ((struct ng_session *) ev.data.ptr)->protocol, + ((struct ng_session *) ev.data.ptr)->socket); + } if (pthread_mutex_lock(&lock)) log_android(ANDROID_LOG_ERROR, "pthread_mutex_lock failed"); @@ -240,9 +223,18 @@ void *handle_events(void *a) { // Check upstream int error = 0; - if (ev.data.ptr == NULL) { + if (ev.data.ptr == &ev_pipe) { + stopping = 1; + uint8_t buffer[1]; + if (read(pipefds[0], buffer, 1) < 0) + log_android(ANDROID_LOG_WARN, "Read pipe error %d: %s", errno, strerror(errno)); + else + log_android(ANDROID_LOG_WARN, "Read pipe"); + + } else if (ev.data.ptr == NULL) { if (check_tun(args, &ev, epoll_fd, sessions, maxsessions) < 0) error = 1; + } else { #ifdef PROFILE_EVENTS gettimeofday(&end, NULL);