X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=lib%2Fsocket.c;h=1bb34f0ef9e57212d7919d4fee3d0d524c3488f6;hb=f96b24fadad7dddbd4162bf8fdb2e9c9206bb2a7;hp=00c65ddbc146aadb2270795cca102789c4eef154;hpb=1744ef90110e99efc5b3c10953ff664b7276517c;p=deb_libnfs.git diff --git a/lib/socket.c b/lib/socket.c index 00c65dd..1bb34f0 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -90,7 +90,7 @@ int rpc_which_events(struct rpc_context *rpc) static int rpc_write_to_socket(struct rpc_context *rpc) { - ssize_t count; + int64_t count; if (rpc == NULL) { return -1; @@ -101,7 +101,7 @@ static int rpc_write_to_socket(struct rpc_context *rpc) } while (rpc->outqueue != NULL) { - ssize_t total; + int64_t total; total = rpc->outqueue->outdata.size; @@ -134,7 +134,7 @@ static int rpc_read_from_socket(struct rpc_context *rpc) int available; int size; int pdu_size; - ssize_t count; + int64_t count; #if defined(WIN32) if (ioctlsocket(rpc->fd, FIONREAD, &available) != 0) { @@ -278,12 +278,16 @@ int rpc_service(struct rpc_context *rpc, int revents) rpc_set_error(rpc, "rpc_service: POLLERR, " "Unknown socket error."); } - rpc->connect_cb(rpc, RPC_STATUS_ERROR, rpc->error_string, rpc->connect_data); + if (rpc->connect_cb != NULL) { + rpc->connect_cb(rpc, RPC_STATUS_ERROR, rpc->error_string, rpc->connect_data); + } return -1; } if (revents & POLLHUP) { rpc_set_error(rpc, "Socket failed with POLLHUP"); - rpc->connect_cb(rpc, RPC_STATUS_ERROR, rpc->error_string, rpc->connect_data); + if (rpc->connect_cb != NULL) { + rpc->connect_cb(rpc, RPC_STATUS_ERROR, rpc->error_string, rpc->connect_data); + } return -1; } @@ -299,13 +303,17 @@ int rpc_service(struct rpc_context *rpc, int revents) rpc_set_error(rpc, "rpc_service: socket error " "%s(%d) while connecting.", strerror(err), err); - rpc->connect_cb(rpc, RPC_STATUS_ERROR, + if (rpc->connect_cb != NULL) { + rpc->connect_cb(rpc, RPC_STATUS_ERROR, NULL, rpc->connect_data); + } return -1; } rpc->is_connected = 1; - rpc->connect_cb(rpc, RPC_STATUS_SUCCESS, NULL, rpc->connect_data); + if (rpc->connect_cb != NULL) { + rpc->connect_cb(rpc, RPC_STATUS_SUCCESS, NULL, rpc->connect_data); + } return 0; } @@ -355,8 +363,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. @@ -371,39 +377,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; } @@ -480,6 +490,7 @@ static void reconnect_cb(struct rpc_context *rpc, int status, void *data _U_, vo } rpc->is_connected = 1; + rpc->connect_cb = NULL; } /* disconnect but do not error all PDUs, just move pdus in-flight back to the outqueue and reconnect */