X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=lib%2Fsocket.c;h=bc101e7a6821b01b78d987bd5e8aad917ecfe126;hb=5a1f14543499d49219245b3c0c274ca8c35919c1;hp=f2943cdfb4c1c7d379ae2f189206d0d8580215be;hpb=bb4e9ed6a88713f6d1da1985f0235bd71d85d017;p=deb_libnfs.git diff --git a/lib/socket.c b/lib/socket.c index f2943cd..bc101e7 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -14,13 +14,8 @@ You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ - -#if defined(WIN32) -#include -#include -#include -#define ssize_t SSIZE_T -#define MSG_DONTWAIT 0 +#ifdef WIN32 +#include "win32_compat.h" #else #include #include @@ -28,7 +23,7 @@ #include #include #include -#endif +#endif/*WIN32*/ #ifdef HAVE_CONFIG_H #include "config.h" @@ -52,16 +47,24 @@ #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 +#endif //FIXME } int rpc_get_fd(struct rpc_context *rpc) @@ -140,6 +143,7 @@ static int rpc_read_from_socket(struct rpc_context *rpc) rpc_set_error(rpc, "Ioctl FIONREAD returned error : %d. Closing socket.", errno); return -1; } + if (available == 0) { rpc_set_error(rpc, "Socket has been closed"); return -1; @@ -254,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, @@ -302,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; } } @@ -317,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; @@ -359,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; } @@ -497,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; +}