Esempio n. 1
0
void *handle_events(void *a) {
    int sdk;
    fd_set rfds;
    fd_set wfds;
    fd_set efds;
    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);

    // Attach to Java
    JNIEnv *env;
    jint rs = (*jvm)->AttachCurrentThread(jvm, &env, NULL);
    if (rs != JNI_OK) {
        log_android(ANDROID_LOG_ERROR, "AttachCurrentThread failed");
        return NULL;
    }
    args->env = env;

    // Get SDK version
    sdk = sdk_int(env);

    int maxsessions = 1024;
    struct rlimit rlim;
    if (getrlimit(RLIMIT_NOFILE, &rlim))
        log_android(ANDROID_LOG_WARN, "getrlimit error %d: %s", errno, strerror(errno));
    else {
        maxsessions = rlim.rlim_cur * 80 / 100;
        log_android(ANDROID_LOG_WARN, "getrlimit soft %d hard %d max sessions %d",
                    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;

    // Loop
    while (!stopping) {
        log_android(ANDROID_LOG_DEBUG, "Loop thread %x", thread_id);

        // Count sessions
        int isessions = get_icmp_sessions();
        int usessions = get_udp_sessions();
        int tsessions = get_tcp_sessions();
        int sessions = isessions + usessions + tsessions;

        // Check sessions
        check_icmp_sessions(args, sessions, maxsessions);
        check_udp_sessions(args, sessions, maxsessions);
        check_tcp_sessions(args, sessions, maxsessions);

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

        // Next event time
        ts.tv_sec = (sdk < 16 ? 5 : get_select_timeout(sessions, maxsessions));
        ts.tv_nsec = 0;
        sigemptyset(&emptyset);

        // Check if tun is writable
        FD_ZERO(&rfds);
        FD_ZERO(&wfds);
        FD_ZERO(&efds);
        FD_SET(args->tun, &wfds);
        if (pselect(args->tun + 1, &rfds, &wfds, &efds, &ts, &emptyset) == 0) {
            log_android(ANDROID_LOG_WARN, "tun not writable");
            continue;
        }

        // Select
        int max = get_selects(args, &rfds, &wfds, &efds);
        int ready = pselect(max + 1, &rfds, &wfds, &efds, idle ? NULL : &ts, &emptyset);

        if (ready < 0) {
            if (errno == EINTR) {
                if (stopping && signaled) { ;
                    log_android(ANDROID_LOG_WARN,
                                "pselect signaled tun %d thread %x", args->tun, thread_id);
                    report_exit(args, NULL);
                    break;
                } else {
                    // TODO check if SIGUSR1 is free
                    log_android(ANDROID_LOG_DEBUG,
                                "pselect interrupted tun %d thread %x", args->tun, thread_id);
                    continue;
                }
            } else if (errno == EBADF) {
                struct stat sb;
                if (fstat(args->tun, &sb) < 0) {
                    log_android(ANDROID_LOG_ERROR,
                                "tun socket %d select error %d: %s",
                                args->tun, errno, strerror(errno));
                    report_exit(args, "tun socket %d select error %d: %s",
                                args->tun, errno, strerror(errno));
                }
                else {
                    log_android(ANDROID_LOG_WARN, "pselect EBADF");
                    break;
                }
            } else {
                log_android(ANDROID_LOG_ERROR,
                            "pselect tun %d thread %x error %d: %s",
                            args->tun, thread_id, errno, strerror(errno));
                report_exit(args, "pselect tun %d thread %x error %d: %s",
                            args->tun, thread_id, errno, strerror(errno));
                break;
            }
        }

        if (ready == 0)
            log_android(ANDROID_LOG_DEBUG, "pselect timeout");
        else {
            log_android(ANDROID_LOG_DEBUG, "pselect ready %d", ready);

            if (pthread_mutex_lock(&lock))
                log_android(ANDROID_LOG_ERROR, "pthread_mutex_lock failed");

#ifdef PROFILE_EVENTS
            struct timeval start, end;
            float mselapsed;
            gettimeofday(&start, NULL);
#endif

            // Check upstream
            int error = 0;
            if (check_tun(args, &rfds, &wfds, &efds, sessions, maxsessions) < 0)
                error = 1;
            else {
#ifdef PROFILE_EVENTS
                gettimeofday(&end, NULL);
                mselapsed = (end.tv_sec - start.tv_sec) * 1000.0 +
                            (end.tv_usec - start.tv_usec) / 1000.0;
                if (mselapsed > PROFILE_EVENTS)
                    log_android(ANDROID_LOG_WARN, "tun %f", mselapsed);

                gettimeofday(&start, NULL);
#endif

                // Check ICMP downstream
                check_icmp_sockets(args, &rfds, &wfds, &efds);

                // Check UDP downstream
                check_udp_sockets(args, &rfds, &wfds, &efds);

                // Check TCP downstream
                check_tcp_sockets(args, &rfds, &wfds, &efds);
            }

            if (pthread_mutex_unlock(&lock))
                log_android(ANDROID_LOG_ERROR, "pthread_mutex_unlock failed");

            if (error)
                break;

#ifdef PROFILE_EVENTS
            gettimeofday(&end, NULL);
            mselapsed = (end.tv_sec - start.tv_sec) * 1000.0 +
                        (end.tv_usec - start.tv_usec) / 1000.0;
            if (mselapsed > PROFILE_EVENTS)
                log_android(ANDROID_LOG_WARN, "sockets %f", mselapsed);
#endif
        }
    }

    (*env)->DeleteGlobalRef(env, args->instance);

    // Detach from Java
    rs = (*jvm)->DetachCurrentThread(jvm);
    if (rs != JNI_OK)
        log_android(ANDROID_LOG_ERROR, "DetachCurrentThread failed");

    // Cleanup
    free(args);

    log_android(ANDROID_LOG_WARN, "Stopped events tun=%d thread %x", args->tun, thread_id);
    thread_id = 0;
    return NULL;
}
Esempio n. 2
0
File: tun.c Progetto: cyrillos/criu
int main(int argc, char **argv)
{
	int fds[5], ret;
	char addr[ETH_ALEN], a2[ETH_ALEN];

	test_init(argc, argv);
#ifdef TUN_NS
	if (unshare(CLONE_NEWNET)) {
		pr_perror("unshare");
		return 1;
	}
	system("ip link set up dev lo");
#endif
	/* fd[0] -- opened file */
	fds[0] = __open_tun();
	if (fds[0] < 0) {
		pr_perror("No file 0");
		return 1;
	}

	/* fd[1] -- opened file with tun device */
	fds[1] = open_tun("tunx0", IFF_TUN);
	if (fds[1] < 0) {
		pr_perror("No file 1");
		return 1;
	}

	/* fd[2] and [3] -- two-queued device, with 3 detached */
	fds[2] = open_tun("tunx1", IFF_TUN | IFF_MULTI_QUEUE);
	if (fds[2] < 0) {
		pr_perror("No file 2");
		return 1;
	}

	fds[3] = open_tun("tunx1", IFF_TUN | IFF_MULTI_QUEUE);
	if (fds[3] < 0) {
		pr_perror("No file 3");
		return 1;
	}

	ret = set_tun_queue(fds[3], "tunx1", IFF_DETACH_QUEUE);
	if (ret < 0)
		return 1;

	/* special case -- persistent device */
	ret = open_tun("tunx2", IFF_TUN);
	if (ret < 0) {
		pr_perror("No persistent device");
		return 1;
	}

	if (ioctl(ret, TUNSETPERSIST, 1) < 0) {
		pr_perror("Can't make persistent");
		return 1;
	}

	/* and one tap in fd[4] */
	fds[4] = open_tun("tapx0", IFF_TAP);
	if (fds[4] < 0) {
		pr_perror("No tap");
		return 1;
	}

	if (dev_get_hwaddr(fds[4], "tapx0", addr) < 0) {
		pr_perror("No hwaddr for tap?");
		return 1;
	}

	close(ret);

	test_daemon();
	test_waitsig();

	/* check fds[0] is not attached to device */
	ret = __attach_tun(fds[0], "tunx3", IFF_TUN);
	if (ret < 0) {
		any_fail = 1;
		fail("Opened tun file broken");
	}

	/* check that fds[1] has device */
	check_tun(fds[1], "tunx0", IFF_TUN);

	/* check that fds[2] and [3] are at MQ device with */
	check_tun(fds[2], "tunx1", IFF_TUN | IFF_MULTI_QUEUE);
	check_tun(fds[3], "tunx1", IFF_TUN | IFF_MULTI_QUEUE);

	ret = set_tun_queue(fds[2], "tunx1", IFF_DETACH_QUEUE);
	if (ret < 0) {
		any_fail = 1;
		fail("Queue not attached");
	}

	ret = set_tun_queue(fds[3], "tunx1", IFF_ATTACH_QUEUE);
	if (ret < 0) {
		any_fail = 1;
		fail("Queue not detached");
	}

	/* check persistent device */
	ret = open_tun("tunx2", IFF_TUN | IFF_TUN_EXCL);
	if (ret >= 0) {
		any_fail = 1;
		fail("Persistent device lost");
	} else {
		ret = open_tun("tunx2", IFF_TUN);
		if (ret < 0)
			pr_perror("Can't attach tun2");
		else
			ioctl(ret, TUNSETPERSIST, 0);
	}

	check_tun(fds[4], "tapx0", IFF_TAP);
	if (dev_get_hwaddr(fds[4], "tapx0", a2) < 0) {
		pr_perror("No hwaddr for tap? (2)");
		any_fail = 1;
	} else if (memcmp(addr, a2, sizeof(addr))) {
		fail("Address mismatch on tap %x:%x -> %x:%x",
				(int)addr[0], (int)addr[1],
				(int)a2[0], (int)a2[1]);
		any_fail = 1;
	}

	if (!any_fail)
		pass();

	return 0;
}