summary refs log tree commit diff stats
path: root/linux-user/syscall.c
diff options
context:
space:
mode:
authorAndreas Schwab <schwab@suse.de>2019-05-13 11:06:26 +0200
committerLaurent Vivier <laurent@vivier.eu>2020-02-19 11:17:40 +0100
commit405dc4cfc62a7c526405c8aba9152c2ac19b588e (patch)
treecf1a5541791abf4b22dce6bcf5e31fbdc12c5771 /linux-user/syscall.c
parent8500476f3cc4d9e1f710290be9fcf86429dd8dda (diff)
downloadfocaccia-qemu-405dc4cfc62a7c526405c8aba9152c2ac19b588e.tar.gz
focaccia-qemu-405dc4cfc62a7c526405c8aba9152c2ac19b588e.zip
linux-user: implement getsockopt SO_RCVTIMEO and SO_SNDTIMEO
Signed-off-by: Andreas Schwab <schwab@suse.de>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Message-Id: <mvmlfzaoh9p.fsf@suse.de>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r--linux-user/syscall.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 7aaa9d9639..9fa722f238 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2310,10 +2310,42 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
         level = SOL_SOCKET;
         switch (optname) {
         /* These don't just return a single integer */
-        case TARGET_SO_RCVTIMEO:
-        case TARGET_SO_SNDTIMEO:
         case TARGET_SO_PEERNAME:
             goto unimplemented;
+        case TARGET_SO_RCVTIMEO: {
+            struct timeval tv;
+            socklen_t tvlen;
+
+            optname = SO_RCVTIMEO;
+
+get_timeout:
+            if (get_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            if (len < 0) {
+                return -TARGET_EINVAL;
+            }
+
+            tvlen = sizeof(tv);
+            ret = get_errno(getsockopt(sockfd, level, optname,
+                                       &tv, &tvlen));
+            if (ret < 0) {
+                return ret;
+            }
+            if (len > sizeof(struct target_timeval)) {
+                len = sizeof(struct target_timeval);
+            }
+            if (copy_to_user_timeval(optval_addr, &tv)) {
+                return -TARGET_EFAULT;
+            }
+            if (put_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            break;
+        }
+        case TARGET_SO_SNDTIMEO:
+            optname = SO_SNDTIMEO;
+            goto get_timeout;
         case TARGET_SO_PEERCRED: {
             struct ucred cr;
             socklen_t crlen;