Fixed errno processing for connect() on Windows.
[deb_libnfs.git] / lib / socket.c
index 0f12697388779cd3f819bcf39c22227c0ddf225d..3fa8378d9102b0127ded464dd9439d47258a7a53 100644 (file)
@@ -33,8 +33,6 @@
 #include <fcntl.h>
 #include <string.h>
 #include <errno.h>
-#include <rpc/rpc.h>
-#include <rpc/xdr.h>
 #ifdef HAVE_SYS_FILIO_H
 #include <sys/filio.h>
 #endif
@@ -42,6 +40,7 @@
 #include <sys/sockio.h>
 #endif
 #include <sys/types.h>
+#include "libnfs-zdr.h"
 #include "libnfs.h"
 #include "libnfs-raw.h"
 #include "libnfs-private.h"
@@ -90,7 +89,7 @@ int rpc_which_events(struct rpc_context *rpc)
 
 static int rpc_write_to_socket(struct rpc_context *rpc)
 {
-       int64_t count;
+       int32_t count;
 
        if (rpc == NULL) {
                return -1;
@@ -134,7 +133,7 @@ static int rpc_read_from_socket(struct rpc_context *rpc)
        int available;
        int size;
        int pdu_size;
-       int64_t count;
+       int32_t count;
 
 #if defined(WIN32)
        if (ioctlsocket(rpc->fd, FIONREAD, &available) != 0) {
@@ -363,8 +362,6 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
                return -1;
        }
 
-
-#if !defined(WIN32)
        /* Some systems allow you to set capabilities on an executable
         * to allow the file to be executed with privilege to bind to
         * privileged system ports, even if the user is not root.
@@ -379,39 +376,43 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
         * On linux, use
         *    sudo setcap 'cap_net_bind_service=+ep' /path/executable
         * to make the executable able to bind to a system port.
+        *
+        * On Windows, there is no concept of privileged ports. Thus
+        * binding will usually succeed.
         */
-       if (1) {
-               int port;
-               int one = 1;
-
-               setsockopt(rpc->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
-
-               for (port = 200; port < 500; port++) {
-                       struct sockaddr_in sin;
-
-                       memset(&sin, 0, sizeof(sin));
-                       sin.sin_port        = htons(port);
-                       sin.sin_family      = AF_INET;
-                       sin.sin_addr.s_addr = 0;
-
-                       if (bind(rpc->fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) != 0 && errno != EACCES) {
-                               /* we didnt get EACCES, so try again */
-                               continue;
+       {
+               struct sockaddr_in sin;
+               static int portOfs = 0;
+               const int firstPort = 512;      /* >= 512 according to Sun docs */
+               const int portCount = IPPORT_RESERVED - firstPort;
+               int startOfs = portOfs, port, rc;
+
+               do {
+                       rc = -1;
+                       port = htons(firstPort + portOfs);
+                       portOfs = (portOfs + 1) % portCount;
+
+                       /* skip well-known ports */
+                       if (!getservbyport(port, "tcp")) {
+                               memset(&sin, 0, sizeof(sin));
+                               sin.sin_port        = port;
+                               sin.sin_family      = AF_INET;
+                               sin.sin_addr.s_addr = 0;
+
+                               rc = bind(rpc->fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
+#if !defined(WIN32)
+                               /* we got EACCES, so don't try again */
+                               if (rc != 0 && errno == EACCES)
+                                       break;
+#endif
                        }
-                       break;
-               }
+               } while (rc != 0 && portOfs != startOfs);
        }
-#endif
 
        set_nonblocking(rpc->fd);
 
-#if defined(WIN32)
-       if (connect(rpc->fd, (struct sockaddr *)s, socksize) == 0 && errno != EINPROGRESS   )
-#else
-       if (connect(rpc->fd, (struct sockaddr *)s, socksize) != 0 && errno != EINPROGRESS) 
-#endif
-       {
-               rpc_set_error(rpc, "connect() to server failed");
+       if (connect(rpc->fd, (struct sockaddr *)s, socksize) != 0 && errno != EINPROGRESS) {
+               rpc_set_error(rpc, "connect() to server failed. %s(%d)", strerror(errno), errno);
                return -1;
        }