]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
Attempt to make sockets code work right on windows.
authorNick Mathewson <nickm@torproject.org>
Thu, 14 Aug 2003 17:13:52 +0000 (17:13 +0000)
committerNick Mathewson <nickm@torproject.org>
Thu, 14 Aug 2003 17:13:52 +0000 (17:13 +0000)
svn:r398

12 files changed:
src/common/fakepoll.c
src/common/util.c
src/common/util.h
src/or/buffers.c
src/or/connection.c
src/or/connection_edge.c
src/or/connection_exit.c
src/or/connection_or.c
src/or/directory.c
src/or/main.c
src/or/or.h
src/or/test.c

index ec1201a797df6cbabce1153c07defdf39d6c3422..17bd18d401810dc39e740130880c73a885d92ecd 100644 (file)
@@ -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)
index 378612d10e6e88d3fd47778f634d0c58a58489fa..dea4b3371940e9f4ceba456cad1f33e1c161c320 100644 (file)
@@ -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
index 3569632e979fe34ef8516dd4b7a63fe08d1e9d40..0590f8ed7aea4eb47da7811b59418658c7fabdf2 100644 (file)
 #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
index 4a89b260d488cfb022da3bff35f968a02fe5bd57..3ea26dbabb6bc71497870e410b0f88da3bcb365f 100644 (file)
@@ -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 {
index c75b4b37931d11bf971dc562685d7aceb8e71e27..78bf0dca552ac10f792825ff988b50e9f610926f 100644 (file)
@@ -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;
index 9ce0ab56ba84046c56d1cce2a0ba89f19e63816a..a2dcaeffd666dacf5ded8210233a0192a3de501e 100644 (file)
@@ -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;
index 1daf9ad8f91a1ba9d84f2eeba988746d3ffbefdd..148f401e9bd3cdfb020468eb4d1ce7eda971da62 100644 (file)
@@ -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;
     }
   }
index ccf3be06ad8768cb3bfa36a620dbf55fdd170ce1..75a02d0d73131b27b890a5ba2ec20fb89d50df9e 100644 (file)
@@ -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;
     }
index 1c4fb95b56229df14772fe66b627a9780fd00ef7..e402123dd2cc79b8daf208f15bcc253ffd34742b 100644 (file)
@@ -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 */
index 9206d7b78b06ccf86ac5c0e58b1da3f7be12fd28..c5206aebc4618eaf01c7a87181ff21c46009b862 100644 (file)
@@ -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 */
index 72bdf0bbba6f38022d2124fec100ecdaf90527c8..83c80a36b0f217b39722ec2af92fbe6d4947aa22 100644 (file)
@@ -89,7 +89,6 @@
 #define snprintf _snprintf
 #endif
 
-
 #include "../common/crypto.h"
 #include "../common/log.h"
 #include "../common/util.h"
index acc3896afd867e6eb0fc894c6babc0b652e1bed1..3d769c39aaccd426241964f17f21caf8ca31f201 100644 (file)
@@ -7,7 +7,7 @@
 #include <fcntl.h>
 #endif
 
-#ifdef _MSC_VER
+#ifdef MS_WINDOWS
 /* For mkdir() */
 #include <direct.h>
 #endif