[win32] - completed win32 port
[deb_libnfs.git] / lib / socket.c
index fe2068c54029c516f53c64ceebf7c0517699cb99..bc101e7a6821b01b78d987bd5e8aad917ecfe126 100644 (file)
 #include <netdb.h>
 #endif/*WIN32*/
 
-#if defined(WIN32)
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <basetsd.h>
-#define ssize_t SSIZE_T
-#define MSG_DONTWAIT 0
-#else
-#include <unistd.h>
-#include <poll.h>
-#include <arpa/inet.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#endif
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 #include "libnfs-private.h"
 #include "slist.h"
 
+#ifdef WIN32
+//has to be included after stdlib!!
+#include "win32_errnowrapper.h"
+#endif
+
+
 static int rpc_disconnect_requeue(struct rpc_context *rpc);
 
 static void set_nonblocking(int fd)
 {
+       int v = 0;
 #if defined(WIN32)
+       long nonblocking=1;
+       v = ioctlsocket(fd, FIONBIO,&nonblocking);
 #else
-       unsigned v;
        v = fcntl(fd, F_GETFL, 0);
         fcntl(fd, F_SETFL, v | O_NONBLOCK);
 #endif //FIXME
@@ -265,7 +258,11 @@ static int rpc_read_from_socket(struct rpc_context *rpc)
 int rpc_service(struct rpc_context *rpc, int revents)
 {
        if (revents & POLLERR) {
+#ifdef WIN32
                char err = 0;
+#else
+               int err = 0;
+#endif
                socklen_t err_size = sizeof(err);
 
                if (getsockopt(rpc->fd, SOL_SOCKET, SO_ERROR,
@@ -313,7 +310,7 @@ int rpc_service(struct rpc_context *rpc, int revents)
 
        if (revents & POLLIN) {
                if (rpc_read_from_socket(rpc) != 0) {
-                       rpc_disconnect_requeue(rpc);
+                       rpc_disconnect_requeue(rpc);
                        return 0;
                }
        }
@@ -328,7 +325,6 @@ int rpc_service(struct rpc_context *rpc, int revents)
        return 0;
 }
 
-
 int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc_cb cb, void *private_data)
 {
        struct sockaddr_storage s;
@@ -370,9 +366,54 @@ int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc
        rpc->connect_cb  = cb;
        rpc->connect_data = private_data;
 
+
+#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.
+        *
+        * Opportunistically try to bind the socket to a low numbered
+        * system port in the hope that the user is either root or the
+        * executable has the CAP_NET_BIND_SERVICE.
+        *
+        * As soon as we fail the bind() with EACCES we know we will never
+        * be able to bind to a system port so we terminate the loop.
+        *
+        * On linux, use
+        *    sudo setcap 'cap_net_bind_service=+ep' /path/executable
+        * to make the executable able to bind to a system port.
+        */
+       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;
+                       }
+                       break;
+               }
+       }
+#endif
+
        set_nonblocking(rpc->fd);
 
-       if (connect(rpc->fd, (struct sockaddr *)&s, socksize) != 0 && errno != EINPROGRESS) {
+#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");
                return -1;
        }               
@@ -508,3 +549,17 @@ struct sockaddr *rpc_get_recv_sockaddr(struct rpc_context *rpc)
 {
        return (struct sockaddr *)&rpc->udp_src;
 }
+
+int rpc_queue_length(struct rpc_context *rpc)
+{
+       int i=0;
+       struct rpc_pdu *pdu;
+
+       for(pdu = rpc->outqueue; pdu; pdu = pdu->next) {
+               i++;
+       }
+       for(pdu = rpc->waitpdu; pdu; pdu = pdu->next) {
+               i++;
+       }
+       return i;
+}