Replace signals by pipe

Refs #431
This commit is contained in:
M66B 2016-06-24 17:44:54 +02:00
parent b1de77be1e
commit af71ba803f
2 changed files with 67 additions and 63 deletions

View File

@ -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

View File

@ -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);