Преглед на файлове

Attempt to make sockets code work right on windows.

svn:r398
Nick Mathewson преди 21 години
родител
ревизия
cd3467bb01
променени са 12 файла, в които са добавени 129 реда и са изтрити 33 реда
  1. 19 4
      src/common/fakepoll.c
  2. 21 8
      src/common/util.c
  3. 27 1
      src/common/util.h
  4. 20 2
      src/or/buffers.c
  5. 11 1
      src/or/connection.c
  6. 1 1
      src/or/connection_edge.c
  7. 4 2
      src/or/connection_exit.c
  8. 5 3
      src/or/connection_or.c
  9. 5 3
      src/or/directory.c
  10. 15 6
      src/or/main.c
  11. 0 1
      src/or/or.h
  12. 1 1
      src/or/test.c

+ 19 - 4
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)

+ 21 - 8
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

+ 27 - 1
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

+ 20 - 2
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 {

+ 11 - 1
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;

+ 1 - 1
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;

+ 4 - 2
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;
     }
   }

+ 5 - 3
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;
     }

+ 5 - 3
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 */

+ 15 - 6
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 */

+ 0 - 1
src/or/or.h

@@ -89,7 +89,6 @@
 #define snprintf _snprintf
 #endif
 
-
 #include "../common/crypto.h"
 #include "../common/log.h"
 #include "../common/util.h"

+ 1 - 1
src/or/test.c

@@ -7,7 +7,7 @@
 #include <fcntl.h>
 #endif
 
-#ifdef _MSC_VER
+#ifdef MS_WINDOWS
 /* For mkdir() */
 #include <direct.h>
 #endif