#include "timeout.h"
 #include "control.h"
+#include "util.h"
 
 static int control_fd = -1;
 
 
        for (ai = result; ai; ai = ai->ai_next) {
                int fd;
-               int val = 1;
 
                fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
                if (fd < 0)
                        break;
                }
 
-               if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
-                              &val, sizeof(val)) < 0) {
-                       perror("setsockopt");
-                       exit(EXIT_FAILURE);
-               }
+               setsockopt_int_check(fd, SOL_SOCKET, SO_REUSEADDR, 1,
+                                    "setsockopt SO_REUSEADDR");
 
                if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0)
                        goto next;
 
 
 #include "msg_zerocopy_common.h"
 
-void enable_so_zerocopy(int fd)
-{
-       int val = 1;
-
-       if (setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &val, sizeof(val))) {
-               perror("setsockopt");
-               exit(EXIT_FAILURE);
-       }
-}
-
 void vsock_recv_completion(int fd, const bool *zerocopied)
 {
        struct sock_extended_err *serr;
 
 #define VSOCK_RECVERR  1
 #endif
 
-void enable_so_zerocopy(int fd);
 void vsock_recv_completion(int fd, const bool *zerocopied);
 
 #endif /* MSG_ZEROCOPY_COMMON_H */
 
 
        free(iovec);
 }
+
+/* Set "unsigned long long" socket option and check that it's indeed set */
+void setsockopt_ull_check(int fd, int level, int optname,
+                         unsigned long long val, char const *errmsg)
+{
+       unsigned long long chkval;
+       socklen_t chklen;
+       int err;
+
+       err = setsockopt(fd, level, optname, &val, sizeof(val));
+       if (err) {
+               fprintf(stderr, "setsockopt err: %s (%d)\n",
+                       strerror(errno), errno);
+               goto fail;
+       }
+
+       chkval = ~val; /* just make storage != val */
+       chklen = sizeof(chkval);
+
+       err = getsockopt(fd, level, optname, &chkval, &chklen);
+       if (err) {
+               fprintf(stderr, "getsockopt err: %s (%d)\n",
+                       strerror(errno), errno);
+               goto fail;
+       }
+
+       if (chklen != sizeof(chkval)) {
+               fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val),
+                       chklen);
+               goto fail;
+       }
+
+       if (chkval != val) {
+               fprintf(stderr, "value mismatch: set %llu got %llu\n", val,
+                       chkval);
+               goto fail;
+       }
+       return;
+fail:
+       fprintf(stderr, "%s  val %llu\n", errmsg, val);
+       exit(EXIT_FAILURE);
+;
+}
+
+/* Set "int" socket option and check that it's indeed set */
+void setsockopt_int_check(int fd, int level, int optname, int val,
+                         char const *errmsg)
+{
+       int chkval;
+       socklen_t chklen;
+       int err;
+
+       err = setsockopt(fd, level, optname, &val, sizeof(val));
+       if (err) {
+               fprintf(stderr, "setsockopt err: %s (%d)\n",
+                       strerror(errno), errno);
+               goto fail;
+       }
+
+       chkval = ~val; /* just make storage != val */
+       chklen = sizeof(chkval);
+
+       err = getsockopt(fd, level, optname, &chkval, &chklen);
+       if (err) {
+               fprintf(stderr, "getsockopt err: %s (%d)\n",
+                       strerror(errno), errno);
+               goto fail;
+       }
+
+       if (chklen != sizeof(chkval)) {
+               fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val),
+                       chklen);
+               goto fail;
+       }
+
+       if (chkval != val) {
+               fprintf(stderr, "value mismatch: set %d got %d\n", val, chkval);
+               goto fail;
+       }
+       return;
+fail:
+       fprintf(stderr, "%s val %d\n", errmsg, val);
+       exit(EXIT_FAILURE);
+}
+
+static void mem_invert(unsigned char *mem, size_t size)
+{
+       size_t i;
+
+       for (i = 0; i < size; i++)
+               mem[i] = ~mem[i];
+}
+
+/* Set "timeval" socket option and check that it's indeed set */
+void setsockopt_timeval_check(int fd, int level, int optname,
+                             struct timeval val, char const *errmsg)
+{
+       struct timeval chkval;
+       socklen_t chklen;
+       int err;
+
+       err = setsockopt(fd, level, optname, &val, sizeof(val));
+       if (err) {
+               fprintf(stderr, "setsockopt err: %s (%d)\n",
+                       strerror(errno), errno);
+               goto fail;
+       }
+
+        /* just make storage != val */
+       chkval = val;
+       mem_invert((unsigned char *)&chkval, sizeof(chkval));
+       chklen = sizeof(chkval);
+
+       err = getsockopt(fd, level, optname, &chkval, &chklen);
+       if (err) {
+               fprintf(stderr, "getsockopt err: %s (%d)\n",
+                       strerror(errno), errno);
+               goto fail;
+       }
+
+       if (chklen != sizeof(chkval)) {
+               fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val),
+                       chklen);
+               goto fail;
+       }
+
+       if (memcmp(&chkval, &val, sizeof(val)) != 0) {
+               fprintf(stderr, "value mismatch: set %ld:%ld got %ld:%ld\n",
+                       val.tv_sec, val.tv_usec, chkval.tv_sec, chkval.tv_usec);
+               goto fail;
+       }
+       return;
+fail:
+       fprintf(stderr, "%s val %ld:%ld\n", errmsg, val.tv_sec, val.tv_usec);
+       exit(EXIT_FAILURE);
+}
+
+void enable_so_zerocopy_check(int fd)
+{
+       setsockopt_int_check(fd, SOL_SOCKET, SO_ZEROCOPY, 1,
+                            "setsockopt SO_ZEROCOPY");
+}
 
 struct iovec *alloc_test_iovec(const struct iovec *test_iovec, int iovnum);
 void free_test_iovec(const struct iovec *test_iovec,
                     struct iovec *iovec, int iovnum);
+void setsockopt_ull_check(int fd, int level, int optname,
+                         unsigned long long val, char const *errmsg);
+void setsockopt_int_check(int fd, int level, int optname, int val,
+                         char const *errmsg);
+void setsockopt_timeval_check(int fd, int level, int optname,
+                             struct timeval val, char const *errmsg);
+void enable_so_zerocopy_check(int fd);
 #endif /* UTIL_H */
 
        close(fd);
 }
 
+static void enable_so_zerocopy(int fd)
+{
+       int val = 1;
+
+       if (setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &val, sizeof(val))) {
+               perror("setsockopt");
+               exit(EXIT_FAILURE);
+       }
+}
+
 static void run_sender(int peer_cid, unsigned long to_send_bytes)
 {
        time_t tx_begin_ns;
 
 
        sock_buf_size = SOCK_BUF_SIZE;
 
-       if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
-                      &sock_buf_size, sizeof(sock_buf_size))) {
-               perror("setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)");
-               exit(EXIT_FAILURE);
-       }
+       setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
+                            sock_buf_size,
+                            "setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)");
 
-       if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
-                      &sock_buf_size, sizeof(sock_buf_size))) {
-               perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
-               exit(EXIT_FAILURE);
-       }
+       setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
+                            sock_buf_size,
+                            "setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
 
        /* Ready to receive data. */
        control_writeln("SRVREADY");
        tv.tv_sec = RCVTIMEO_TIMEOUT_SEC;
        tv.tv_usec = 0;
 
-       if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)) == -1) {
-               perror("setsockopt(SO_RCVTIMEO)");
-               exit(EXIT_FAILURE);
-       }
+       setsockopt_timeval_check(fd, SOL_SOCKET, SO_RCVTIMEO, tv,
+                                "setsockopt(SO_RCVTIMEO)");
 
        read_enter_ns = current_nsec();
 
                exit(EXIT_FAILURE);
        }
 
-       if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT,
-                      &lowat_val, sizeof(lowat_val))) {
-               perror("setsockopt(SO_RCVLOWAT)");
-               exit(EXIT_FAILURE);
-       }
+       setsockopt_int_check(fd, SOL_SOCKET, SO_RCVLOWAT,
+                            lowat_val, "setsockopt(SO_RCVLOWAT)");
 
        control_expectln("SRVSENT");
 
        /* size_t can be < unsigned long long */
        sock_buf_size = buf_size;
 
-       if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
-                      &sock_buf_size, sizeof(sock_buf_size))) {
-               perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
-               exit(EXIT_FAILURE);
-       }
+       setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
+                            sock_buf_size,
+                            "setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
 
        if (low_rx_bytes_test) {
                /* Set new SO_RCVLOWAT here. This enables sending credit
                 */
                recv_buf_size = 1 + VIRTIO_VSOCK_MAX_PKT_BUF_SIZE;
 
-               if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT,
-                              &recv_buf_size, sizeof(recv_buf_size))) {
-                       perror("setsockopt(SO_RCVLOWAT)");
-                       exit(EXIT_FAILURE);
-               }
+               setsockopt_int_check(fd, SOL_SOCKET, SO_RCVLOWAT,
+                                    recv_buf_size, "setsockopt(SO_RCVLOWAT)");
        }
 
        /* Send one dummy byte here, because 'setsockopt()' above also
                recv_buf_size++;
 
                /* Updating SO_RCVLOWAT will send credit update. */
-               if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT,
-                              &recv_buf_size, sizeof(recv_buf_size))) {
-                       perror("setsockopt(SO_RCVLOWAT)");
-                       exit(EXIT_FAILURE);
-               }
+               setsockopt_int_check(fd, SOL_SOCKET, SO_RCVLOWAT,
+                                    recv_buf_size, "setsockopt(SO_RCVLOWAT)");
        }
 
        fds.fd = fd;
 
        }
 
        if (test_data->so_zerocopy)
-               enable_so_zerocopy(fd);
+               enable_so_zerocopy_check(fd);
 
        iovec = alloc_test_iovec(test_data->vecs, test_data->vecs_cnt);
 
 
        }
 
        if (msg_zerocopy)
-               enable_so_zerocopy(fd);
+               enable_so_zerocopy_check(fd);
 
        iovec = alloc_test_iovec(test_data->vecs, test_data->vecs_cnt);