diff options
author | Nick Mathewson <nickm@torproject.org> | 2003-08-14 17:13:52 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2003-08-14 17:13:52 +0000 |
commit | cd3467bb01cb5bd98b2978fb50bdaa2f3227c980 (patch) | |
tree | d91d3689a009c3fa358bae94e883240e83fcb642 | |
parent | 88edae94076cc39d40a39f80b2d6ddadc88fe324 (diff) | |
download | tor-cd3467bb01cb5bd98b2978fb50bdaa2f3227c980.tar tor-cd3467bb01cb5bd98b2978fb50bdaa2f3227c980.tar.gz |
Attempt to make sockets code work right on windows.
svn:r398
-rw-r--r-- | src/common/fakepoll.c | 23 | ||||
-rw-r--r-- | src/common/util.c | 29 | ||||
-rw-r--r-- | src/common/util.h | 28 | ||||
-rw-r--r-- | src/or/buffers.c | 22 | ||||
-rw-r--r-- | src/or/connection.c | 12 | ||||
-rw-r--r-- | src/or/connection_edge.c | 2 | ||||
-rw-r--r-- | src/or/connection_exit.c | 6 | ||||
-rw-r--r-- | src/or/connection_or.c | 8 | ||||
-rw-r--r-- | src/or/directory.c | 8 | ||||
-rw-r--r-- | src/or/main.c | 21 | ||||
-rw-r--r-- | src/or/or.h | 1 | ||||
-rw-r--r-- | src/or/test.c | 2 |
12 files changed, 129 insertions, 33 deletions
diff --git a/src/common/fakepoll.c b/src/common/fakepoll.c index ec1201a79..17bd18d40 100644 --- a/src/common/fakepoll.c +++ b/src/common/fakepoll.c @@ -8,6 +8,7 @@ #include "orconfig.h" #include "fakepoll.h" + #ifdef USE_FAKE_POLL #include <sys/types.h> #ifdef HAVE_UNISTD_H @@ -30,6 +31,9 @@ poll(struct pollfd *ufds, unsigned int nfds, int timeout) { unsigned int idx, maxfd, fd; int r; +#ifdef MS_WINDOWS + int any_fds_set = 0; +#endif fd_set readfds, writefds, exceptfds; #ifdef USING_FAKE_TIMEVAL #undef timeval @@ -46,15 +50,26 @@ poll(struct pollfd *ufds, unsigned int nfds, int timeout) maxfd = -1; for (idx = 0; idx < nfds; ++idx) { fd = ufds[idx].fd; - if (fd > maxfd && ufds[idx].events) - maxfd = fd; - if (ufds[idx].events & (POLLIN)) + if (ufds[idx].events) { + if (fd > maxfd) + maxfd = fd; +#ifdef MS_WINDOWS + any_fds_set = 1; +#endif + } + if (ufds[idx].events & POLLIN) FD_SET(fd, &readfds); if (ufds[idx].events & POLLOUT) FD_SET(fd, &writefds); - if (ufds[idx].events & (POLLERR)) + if (ufds[idx].events & POLLERR) FD_SET(fd, &exceptfds); } +#ifdef MS_WINDOWS + if (!any_fds_set) { + usleep(timeout); + return 0; + } +#endif r = select(maxfd+1, &readfds, &writefds, &exceptfds, timeout == -1 ? NULL : &_timeout); if (r <= 0) diff --git a/src/common/util.c b/src/common/util.c index 378612d10..dea4b3371 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -4,7 +4,7 @@ #include "../or/or.h" -#ifdef _MSC_VER +#ifdef MS_WINDOWS #include <io.h> #include <limits.h> #include <process.h> @@ -90,7 +90,7 @@ void tv_addms(struct timeval *a, long ms) { void set_socket_nonblocking(int socket) { -#ifdef _MSC_VER +#ifdef MS_WINDOWS /* Yes means no and no means yes. Do you not want to be nonblocking? */ int nonblocking = 0; ioctlsocket(socket, FIONBIO, (unsigned long*) &nonblocking); @@ -101,7 +101,7 @@ void set_socket_nonblocking(int socket) int spawn_func(int (*func)(void *), void *data) { -#ifdef _MSC_VER +#ifdef MS_WINDOWS int rv; rv = _beginthread(func, 0, data); if (rv == (unsigned long) -1) @@ -125,7 +125,7 @@ int spawn_func(int (*func)(void *), void *data) void spawn_exit() { -#ifdef _MSC_VER +#ifdef MS_WINDOWS _endthread(); #else exit(0); @@ -137,7 +137,7 @@ void spawn_exit() int tor_socketpair(int family, int type, int protocol, int fd[2]) { -#ifdef HAVE_SOCKETPAIR_XXX +#ifdef HAVE_SOCKETPAIR_XXXX /* For testing purposes, we never fall back to real socketpairs. */ return socketpair(family, type, protocol, fd); #else @@ -153,8 +153,8 @@ tor_socketpair(int family, int type, int protocol, int fd[2]) || family != AF_UNIX #endif ) { -#ifdef _MSC_VER - errno = WSAEAFNOSUPPORT; +#ifdef MS_WINDOWS + errno = WSAEAFNOSUPPORT; #else errno = EAFNOSUPPORT; #endif @@ -213,7 +213,7 @@ tor_socketpair(int family, int type, int protocol, int fd[2]) return 0; abort_tidy_up_and_fail: -#ifdef _MSC_VER +#ifdef MS_WINDOWS errno = WSAECONNABORTED; #else errno = ECONNABORTED; /* I hope this is portable and appropriate. */ @@ -232,3 +232,16 @@ tor_socketpair(int family, int type, int protocol, int fd[2]) } #endif } + +#ifdef MS_WINDOWS +int correct_socket_errno(int s) +{ + int r, optval, optvallen=sizeof(optval); + assert(errno == WSAEWOULDBLOCK); + if (getsockopt(s, SOL_SOCKET, SO_ERROR, (void*)&optval, &optvallen)) + return errno; + if (optval) + return optval; + return WSAEWOULDBLOCK; +} +#endif diff --git a/src/common/util.h b/src/common/util.h index 3569632e9..0590f8ed7 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -13,6 +13,12 @@ #ifdef HAVE_TIME_H #include <time.h> #endif +#if _MSC_VER > 1300 +#include <winsock2.h> +#include <ws2tcpip.h> +#elif defined(_MSC_VER) +#include <winsock.h> +#endif #ifndef HAVE_GETTIMEOFDAY #ifdef HAVE_FTIME #define USING_FAKE_TIMEVAL @@ -23,7 +29,7 @@ #endif #endif -#ifdef _MSC_VER +#ifdef MS_WINDOWS /* Windows names string functions funnily. */ #define strncasecmp strnicmp #define strcasecmp stricmp @@ -55,4 +61,24 @@ void spawn_exit(); int tor_socketpair(int family, int type, int protocol, int fd[2]); +/* For stupid historical reasons, windows sockets have an independent set of + * errnos which they use as the fancy strikes them. + */ +#ifdef MS_WINDOWS +#define ERRNO_EAGAIN(e) ((e) == EAGAIN || \ + (e) == WSAEWOULDBLOCK || \ + (e) == EWOULDBLOCK) +#define ERRNO_EINPROGRESS(e) ((e) == EINPROGRESS || \ + (e) == WSAEINPROGRESS) +#define ERRNO_CONN_EINPROGRESS(e) ((e) == EINPROGRESS || \ + (e) == WSAEINPROGRESS || (e) == WSAEINVAL) +int correct_socket_errno(int s); +#else +#define ERRNO_EAGAIN(e) ((e) == EAGAIN) +#define ERRNO_EINPROGRESS(e) ((e) == EINPROGRESS) +#define ERRNO_CONN_EINPROGRESS(e) ((e) == EINPROGRESS) +#define correct_socket_errno(s) (errno) +#endif + + #endif diff --git a/src/or/buffers.c b/src/or/buffers.c index 4a89b260d..3ea26dbab 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -36,6 +36,9 @@ void buf_free(char *buf) { int read_to_buf(int s, int at_most, char **buf, int *buflen, int *buf_datalen, int *reached_eof) { int read_result; +#ifdef MS_WINDOWS + int e; +#endif assert(buf && *buf && buflen && buf_datalen && reached_eof && (s>=0)); @@ -62,9 +65,15 @@ int read_to_buf(int s, int at_most, char **buf, int *buflen, int *buf_datalen, i // log_fn(LOG_DEBUG,"reading at most %d bytes.",at_most); read_result = read(s, *buf+*buf_datalen, at_most); if (read_result < 0) { - if(errno!=EAGAIN) { /* it's a real error */ + if(!ERRNO_EAGAIN(errno)) { /* it's a real error */ return -1; } +#ifdef MS_WINDOWS + e = correct_socket_errno(s); + if(!ERRNO_EAGAIN(errno)) { /* no, it *is* a real error! */ + return -1; + } +#endif return 0; } else if (read_result == 0) { log_fn(LOG_DEBUG,"Encountered eof"); @@ -84,6 +93,9 @@ int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datale * return -1 or how many bytes remain to be flushed */ int write_result; +#ifdef MS_WINDOWS + int e; +#endif assert(buf && *buf && buflen && buf_flushlen && buf_datalen && (s>=0) && (*buf_flushlen <= *buf_datalen)); @@ -94,9 +106,15 @@ int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datale write_result = write(s, *buf, *buf_flushlen); if (write_result < 0) { - if(errno!=EAGAIN) { /* it's a real error */ + if(!ERRNO_EAGAIN(errno)) { /* it's a real error */ + return -1; + } +#ifdef MS_WINDOWS + e = correct_socket_errno(s); + if(!ERRNO_EAGAIN(errno)) { /* no, it *is* a real error! */ return -1; } +#endif log_fn(LOG_DEBUG,"write() would block, returning."); return 0; } else { diff --git a/src/or/connection.c b/src/or/connection.c index c75b4b379..78bf0dca5 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -188,11 +188,21 @@ int connection_handle_listener_read(connection_t *conn, int new_type, int new_st connection_t *newconn; struct sockaddr_in remote; /* information about the remote peer when connecting to other routers */ int remotelen = sizeof(struct sockaddr_in); /* length of the remote address */ +#ifdef MS_WINDOWS + int e; +#endif news = accept(conn->s,(struct sockaddr *)&remote,&remotelen); if (news == -1) { /* accept() error */ - if(errno==EAGAIN) + if(ERRNO_EAGAIN(errno)) { +#ifdef MS_WINDOWS + e = correct_socket_errno(conn->s); + if (ERRNO_EAGAIN(e)) + return 0; +#else return 0; /* he hung up before we could accept(). that's fine. */ +#endif + } /* else there was a real error. */ log_fn(LOG_ERR,"accept() failed. Closing."); return -1; diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 9ce0ab56b..a2dcaeffd 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -265,7 +265,7 @@ int connection_edge_finished_flushing(connection_t *conn) { switch(conn->state) { case EXIT_CONN_STATE_CONNECTING: if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { /* not yet */ - if(errno != EINPROGRESS){ + if(!ERRNO_CONN_EINPROGRESS(errno)) { /* yuck. kill it. */ log_fn(LOG_DEBUG,"in-progress exit connect failed. Removing."); return -1; diff --git a/src/or/connection_exit.c b/src/or/connection_exit.c index 1daf9ad8f..148f401e9 100644 --- a/src/or/connection_exit.c +++ b/src/or/connection_exit.c @@ -90,7 +90,7 @@ int connection_exit_connect(connection_t *conn) { log_fn(LOG_DEBUG,"Connecting to %s:%u.",conn->address,conn->port); if(connect(s,(struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0) { - if(errno != EINPROGRESS){ + if(!ERRNO_CONN_EINPROGRESS(errno)) { /* yuck. kill it. */ perror("connect"); log_fn(LOG_DEBUG,"Connect failed."); @@ -102,7 +102,9 @@ int connection_exit_connect(connection_t *conn) { conn->state = EXIT_CONN_STATE_CONNECTING; log_fn(LOG_DEBUG,"connect in progress, socket %d.",s); - connection_watch_events(conn, POLLOUT | POLLIN); + connection_watch_events(conn, POLLOUT | POLLIN | POLLERR); + /* writable indicates finish, readable indicates broken link, + error indicates broken link in windowsland. */ return 0; } } diff --git a/src/or/connection_or.c b/src/or/connection_or.c index ccf3be06a..75a02d0d7 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -62,7 +62,7 @@ int connection_or_finished_flushing(connection_t *conn) { return or_handshake_op_finished_sending_keys(conn); case OR_CONN_STATE_CLIENT_CONNECTING: if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { /* not yet */ - if(errno != EINPROGRESS){ + if(!ERRNO_CONN_EINPROGRESS(errno)){ /* yuck. kill it. */ log_fn(LOG_DEBUG,"in-progress connect failed. Removing."); return -1; @@ -156,7 +156,7 @@ connection_t *connection_or_connect(routerinfo_t *router) { log(LOG_DEBUG,"connection_or_connect() : Trying to connect to %s:%u.",router->address,router->or_port); if(connect(s,(struct sockaddr *)&router_addr,sizeof(router_addr)) < 0){ - if(errno != EINPROGRESS){ + if(!ERRNO_CONN_EINPROGRESS(errno)) { /* yuck. kill it. */ connection_free(conn); return NULL; @@ -170,7 +170,9 @@ connection_t *connection_or_connect(routerinfo_t *router) { } log(LOG_DEBUG,"connection_or_connect() : connect in progress."); - connection_watch_events(conn, POLLIN | POLLOUT); /* writable indicates finish, readable indicates broken link */ + connection_watch_events(conn, POLLIN | POLLOUT | POLLERR); + /* writable indicates finish, readable indicates broken link, + error indicates broken link on windows */ conn->state = OR_CONN_STATE_CLIENT_CONNECTING; return conn; } diff --git a/src/or/directory.c b/src/or/directory.c index 1c4fb95b5..e402123dd 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -66,7 +66,7 @@ void directory_initiate_fetch(routerinfo_t *router) { log_fn(LOG_DEBUG,"Trying to connect to %s:%u.",router->address,router->dir_port); if(connect(s,(struct sockaddr *)&router_addr,sizeof(router_addr)) < 0){ - if(errno != EINPROGRESS){ + if(!ERRNO_CONN_EINPROGRESS(errno)) { /* yuck. kill it. */ router_forget_router(conn->addr, conn->port); /* don't try him again */ connection_free(conn); @@ -81,7 +81,9 @@ void directory_initiate_fetch(routerinfo_t *router) { } log_fn(LOG_DEBUG,"connect in progress."); - connection_watch_events(conn, POLLIN | POLLOUT); /* writable indicates finish, readable indicates broken link */ + connection_watch_events(conn, POLLIN | POLLOUT | POLLERR); + /* writable indicates finish, readable indicates broken link, + error indicates broken link in windowsland. */ conn->state = DIR_CONN_STATE_CONNECTING; return; } @@ -255,7 +257,7 @@ int connection_dir_finished_flushing(connection_t *conn) { switch(conn->state) { case DIR_CONN_STATE_CONNECTING: if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { /* not yet */ - if(errno != EINPROGRESS){ + if(!ERRNO_CONN_EINPROGRESS(errno)) { /* yuck. kill it. */ log_fn(LOG_DEBUG,"in-progress connect failed. Removing."); router_forget_router(conn->addr, conn->port); /* don't try him again */ diff --git a/src/or/main.c b/src/or/main.c index 9206d7b78..c5206aebc 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -243,7 +243,6 @@ void connection_start_writing(connection_t *conn) { poll_array[conn->poll_index].events |= POLLOUT; } - static void conn_read(int i) { int retval; connection_t *conn; @@ -252,6 +251,13 @@ static void conn_read(int i) { assert(conn); // log_fn(LOG_DEBUG,"socket %d has something to read.",conn->s); +#ifdef MS_WINDOWS + if (poll_array[i].revents & POLLERR) { + retval = -1; + goto error; + } +#endif + if (conn->type == CONN_TYPE_OR_LISTENER) { retval = connection_or_handle_listener_read(conn); } else if (conn->type == CONN_TYPE_AP_LISTENER) { @@ -274,14 +280,17 @@ static void conn_read(int i) { } } +#ifdef MS_WINDOWS + error: +#endif if(retval < 0) { /* this connection is broken. remove it */ log_fn(LOG_INFO,"%s connection broken, removing.", conn_type_to_string[conn->type]); connection_remove(conn); connection_free(conn); if(i<nfds) { /* we just replaced the one at i with a new one. process it too. */ - if(poll_array[i].revents & POLLIN || - poll_array[i].revents & POLLHUP ) /* something to read */ + if(poll_array[i].revents & (POLLIN|POLLHUP|POLLERR)) + /* something to read */ conn_read(i); } } @@ -565,10 +574,10 @@ static int do_main_loop(void) { } if(poll_result > 0) { /* we have at least one connection to deal with */ - /* do all the reads first, so we can detect closed sockets */ + /* do all the reads and errors first, so we can detect closed sockets */ for(i=0;i<nfds;i++) - if(poll_array[i].revents & POLLIN || - poll_array[i].revents & POLLHUP ) /* something to read */ + if(poll_array[i].revents & (POLLIN|POLLHUP|POLLERR)) + /* something to read, or an error. */ conn_read(i); /* this also blows away broken connections */ /* see http://www.greenend.org.uk/rjk/2001/06/poll.html for discussion * of POLLIN vs POLLHUP */ diff --git a/src/or/or.h b/src/or/or.h index 72bdf0bbb..83c80a36b 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -89,7 +89,6 @@ #define snprintf _snprintf #endif - #include "../common/crypto.h" #include "../common/log.h" #include "../common/util.h" diff --git a/src/or/test.c b/src/or/test.c index acc3896af..3d769c39a 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -7,7 +7,7 @@ #include <fcntl.h> #endif -#ifdef _MSC_VER +#ifdef MS_WINDOWS /* For mkdir() */ #include <direct.h> #endif |