- linux, osx, and ios need rpc/rpc.h includede before rpc/xdr.h
[deb_libnfs.git] / lib / socket.c
index dd4ffc41778eb784d1474acb90a5e2f4122eb005..4701685591793c67f2811aa0b3858c7aa87aef66 100644 (file)
 */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <poll.h>
 #include <string.h>
 #include <errno.h>
+#include <rpc/rpc.h>
 #include <rpc/xdr.h>
 #include <arpa/inet.h>
 #include <sys/ioctl.h>
@@ -43,11 +45,7 @@ int rpc_get_fd(struct rpc_context *rpc)
 
 int rpc_which_events(struct rpc_context *rpc)
 {
-       int events = POLLIN;
-
-       if (rpc->is_connected == 0) {
-               events |= POLLOUT;
-       }       
+       int events = rpc->is_connected ? POLLIN : POLLOUT;
 
        if (rpc->outqueue) {
                events |= POLLOUT;
@@ -168,11 +166,20 @@ static int rpc_read_from_socket(struct rpc_context *rpc)
 int rpc_service(struct rpc_context *rpc, int revents)
 {
        if (revents & POLLERR) {
-               printf("rpc_service: POLLERR, socket error\n");
-               if (rpc->is_connected == 0) {
-                       rpc_set_error(rpc, "Failed to connect to server socket.");
+               int err = 0;
+               socklen_t err_size = sizeof(err);
+
+               if (getsockopt(rpc->fd, SOL_SOCKET, SO_ERROR,
+                               &err, &err_size) != 0 || err != 0) {
+                       if (err == 0) {
+                               err = errno;
+                       }
+                       rpc_set_error(rpc, "rpc_service: socket error "
+                                              "%s(%d).",
+                                              strerror(err), err);
                } else {
-                       rpc_set_error(rpc, "Socket closed with POLLERR");
+                       rpc_set_error(rpc, "rpc_service: POLLERR, "
+                                               "Unknown socket error.");
                }
                rpc->connect_cb(rpc, RPC_STATUS_ERROR, rpc->error_string, rpc->connect_data);
                return -1;
@@ -185,6 +192,22 @@ int rpc_service(struct rpc_context *rpc, int revents)
        }
 
        if (rpc->is_connected == 0 && rpc->fd != -1 && revents&POLLOUT) {
+               int err = 0;
+               socklen_t err_size = sizeof(err);
+
+               if (getsockopt(rpc->fd, SOL_SOCKET, SO_ERROR,
+                               &err, &err_size) != 0 || err != 0) {
+                       if (err == 0) {
+                               err = errno;
+                       }
+                       rpc_set_error(rpc, "rpc_service: socket error "
+                                       "%s(%d) while connecting.",
+                                       strerror(err), err);
+                       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);
                return 0;
@@ -230,8 +253,11 @@ int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc
 
        switch (s.ss_family) {
        case AF_INET:
-               rpc->fd = socket(AF_INET, SOCK_STREAM, 0);
                socksize = sizeof(struct sockaddr_in);
+#ifdef HAVE_SOCK_SIN_LEN
+               sin->sin_len = socksize;
+#endif
+               rpc->fd = socket(AF_INET, SOCK_STREAM, 0);
                break;
        }