[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

I got the onion router to work under windows!



Aside from the missing stdint.h that I mentioned before, there was another
problem that only occurred when the Windows onion router was chosen as an
exit node. The problem was caused by the Windows onion router not detecting
when the connection was closed.

Upon further investigation I discovered that the poll() function was
behaving quite differently when a connection was closed under Windows. More
precisely, under Windows poll() would put POLLHUP into revents instead of
POLLIN as it did under the many different LINUX distributions that I tested
this on. So to get the onion router to work properly under Windows, I simply
added a second condition that would allow the calling of conn_read()
whenever POLLHUP was put into revents by poll() in main.c like this:

        if(poll_array[i].revents & POLLIN ||
           poll_array[i].revents & POLLHUP ) /* something to read */
          conn_read(i); /* this also blows away broken connections */

I have attached a little test program that demonstrates this peculiar
behavior of the poll() function. Here is the output of the test program when
I ran it under Windows and Linux:

Windows
------------------
[montrose@kiwi]$ !gcc
gcc -o bug bug.c -lpthread
[montrose@kiwi]$ ./bug
close: POLLHUP
shutdown: POLLHUP


Linux
------------------
[montrose@ced]$ !gcc
gcc -o bug bug.c -lpthread
[montrose@ced]$ ./bug
close: POLLIN 
shutdown: POLLIN

//
// bug.cxx.  Compile with "gcc -o bug bug.c -lpthread"
//
#include <stdio.h>
#include <memory.h>
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdlib.h>

#define SERVER_PORT 9999

pthread_t tobject;

static void *server_thread(void* arg) {
    int s, conn;
    struct sockaddr_in sa;
    struct pollfd pfd;
    unsigned flags;
    if ( (s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
        perror("socket");
        exit(-1);
    }
    memset (&sa, 0, sizeof (sa));
    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = htonl(INADDR_ANY);
    sa.sin_port = htons(SERVER_PORT);
    if ( bind(s, (struct sockaddr*)&sa, sizeof(sa)) ) {
        perror("bind");
	close(s);
        exit(-1);
    }
    if ( listen(s, 1) ) {
        perror("listen");
	close(s);
        exit(-1);
    }
    conn = accept(s,NULL,NULL);
    if ( conn < 0 ) {
        perror("accept");
	close(s);
	exit(-1);
    }
    flags = fcntl(conn, F_GETFL);
    if ( fcntl(conn, F_SETFL, flags | O_NONBLOCK) ) {
        perror("fcntl");
	close(conn);
	close(s);
        exit(-1);
    }
    pfd.fd = conn;
    pfd.events = POLLIN;
    switch ( poll(&pfd, 1, 10000) ) {
    case 0:
        printf("TIMEOUT\n");
        break;
    case 1:
	if ( pfd.revents & POLLIN ) 	printf("POLLIN ");
	if ( pfd.revents & POLLPRI )	printf("POLLPRI ");
	if ( pfd.revents & POLLERR )	printf("POLLERR ");
	if ( pfd.revents & POLLHUP )	printf("POLLHUP ");
	if ( pfd.revents & POLLNVAL )	printf("POLLNVAL ");
	printf("\n");
        break;
    default:
        perror("poll");
	close(conn);
	close(s);
	exit(-1);
        break;
    }
    close(conn);
    close(s);
}


int conn_test(const char *tname) {
    int conn;
    struct sockaddr_in sa;
    printf("%s: ", tname);
    if ( errno = pthread_create(&tobject, 0, server_thread, 0) ) {
        perror("pthread_create");
        return -1;
    }
    sleep(1);
    if ( (conn = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
        perror("socket");
        return -1;
    }
    memset (&sa, 0, sizeof (sa));
    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = inet_addr("127.0.0.1");
    sa.sin_port = htons(SERVER_PORT);
    if ( connect(conn,(struct sockaddr *)&sa, sizeof(sa)) < 0 ) {
        perror("connect");
	return -1;
    }
    return conn;
}

int main() {
    int conn;
    if ( (conn = conn_test("close")) < 0 ) return -1;
    close(conn);
    pthread_join(tobject, 0);
    if ( (conn = conn_test("shutdown")) < 0 ) return -1;
    shutdown(conn,2);
    pthread_join(tobject, 0);
    return 0;
}