The patch should add support for SO_LINGER, SO_RCVTIMEO, SO_SNDTIMEO, SO_PEERCRED and SO_PEERNAME.
Index: linux-user/syscall.c =================================================================== RCS file: /sources/qemu/qemu/linux-user/syscall.c,v retrieving revision 1.75 diff -u -r1.75 syscall.c --- linux-user/syscall.c 27 Jun 2006 21:08:10 -0000 1.75 +++ linux-user/syscall.c 13 Jul 2006 10:00:09 -0000 @@ -509,20 +509,28 @@ msgh->msg_controllen = tswapl(space); } +static long do_setsockopt_timehelper(int sockfd, int level, int optname, + target_ulong optval, target_ulong optlen) +{ + int len; + struct timeval tv; + if (get_user(len, &optlen) || + !access_ok(VERIFY_READ,optval,sizeof(struct target_timeval))) + return -EFAULT; + + if (len != sizeof(struct target_timeval)) + return -EINVAL; + + target_to_host_timeval(&tv,optval); + return get_errno(setsockopt(sockfd, level, optname, &tv, sizeof(struct timeval))); +} + static long do_setsockopt(int sockfd, int level, int optname, target_ulong optval, socklen_t optlen) { int val, ret; switch(level) { - case SOL_TCP: - /* TCP options all take an 'int' value. */ - if (optlen < sizeof(uint32_t)) - return -EINVAL; - - val = tget32(optval); - ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); - break; case SOL_IP: switch(optname) { case IP_TOS: @@ -606,20 +614,39 @@ optname = SO_RCVLOWAT; break; case TARGET_SO_RCVTIMEO: - optname = SO_RCVTIMEO; + ret = do_setsockopt_timehelper(sockfd,level,SO_RCVTIMEO,optval,optlen); break; case TARGET_SO_SNDTIMEO: - optname = SO_SNDTIMEO; + ret = do_setsockopt_timehelper(sockfd,level,SO_SNDTIMEO,optval,optlen); break; + case TARGET_SO_LINGER: { + struct linger tmp; + struct linger *target = (struct linger *) optval; + if (optlen == sizeof(struct linger) && + get_user(tmp.l_onoff,&target->l_onoff) && + get_user(tmp.l_linger,&target->l_linger)) { + ret = get_errno(setsockopt(sockfd, level, SO_LINGER, &tmp, sizeof(struct linger))); + } else { + /* Just to make strace look better */ + ret = get_errno(setsockopt(sockfd, level, SO_LINGER, &optval,optlen)); + } + return ret; + break; + } break; default: goto unimplemented; } - if (optlen < sizeof(uint32_t)) - return -EINVAL; - - val = tget32(optval); - ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val))); + goto int_case; + break; + case SOL_TCP: + int_case: + /* TCP options all take an 'int' value. */ + if (optlen < sizeof(uint32_t)) + return -EINVAL; + + val = tget32(optval); + ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); break; default: unimplemented: @@ -629,6 +656,40 @@ return ret; } +static long do_getsockopt_structhelper(int sockfd, int level, int optname, + target_ulong optval, target_ulong optlen) +{ + int ret,len,i; + /* Let's assume 32-bit parameters */ + if (get_user(len, &optlen)) + return -EFAULT; + if (len < 0) + return -EINVAL; + ret = get_errno(getsockopt(sockfd, level, optname, &optval, &len)); + for(i = 0; i < len && optval != 0; i += 4) { + /* This could propably be done more efficiently */ + tput32(optval + i, optval + i); + } + return ret; +} + +static long do_getsockopt_timehelper(int sockfd, int level, int optname, + target_ulong optval, target_ulong optlen) +{ + int ret,len; + struct timeval tv; + static socklen_t olen=sizeof(struct timeval); + if (get_user(len, &optlen)) + return -EFAULT; + if (len != sizeof(struct target_timeval)) + return -EINVAL; + ret = get_errno(getsockopt(sockfd, level, optname, &tv, &olen)); + if (ret==0) { + host_to_target_timeval(optval,&tv); + } + return ret; +} + static long do_getsockopt(int sockfd, int level, int optname, target_ulong optval, target_ulong optlen) { @@ -638,13 +699,28 @@ case TARGET_SOL_SOCKET: level = SOL_SOCKET; switch (optname) { + /* These don't just return a single integer */ case TARGET_SO_LINGER: + ret = do_getsockopt_structhelper(sockfd,level,SO_LINGER,optval,optlen); + break; case TARGET_SO_RCVTIMEO: + ret = do_getsockopt_timehelper(sockfd,level,SO_RCVTIMEO,optval,optlen); + break; case TARGET_SO_SNDTIMEO: + ret = do_getsockopt_timehelper(sockfd,level,SO_SNDTIMEO,optval,optlen); + break; case TARGET_SO_PEERCRED: + ret = do_getsockopt_structhelper(sockfd,level,SO_PEERCRED,optval,optlen); + break; case TARGET_SO_PEERNAME: - /* These don't just return a single integer */ - goto unimplemented; + if (get_user(len, &optlen)) + return -EFAULT; + if (len < 0) + return -EINVAL; + ret = get_errno(getsockopt(sockfd, level, optname, &optval, &len)); + if (put_user(len, &optlen)) + return -EFAULT; + break; default: goto int_case; }
Index: linux-user/syscall.c =================================================================== RCS file: /sources/qemu/qemu/linux-user/syscall.c,v retrieving revision 1.75 diff -u -r1.75 syscall.c --- linux-user/syscall.c 27 Jun 2006 21:08:10 -0000 1.75 +++ linux-user/syscall.c 13 Jul 2006 10:00:09 -0000 @@ -1054,6 +1141,13 @@ /* XXX: suppress this function and call directly the related socket functions */ +#if defined(TARGET_NR_accept) || defined(TARGET_NR_getpeername) || \ + defined(TARGET_NR_getsockname) || defined(TARGET_NR_listen) || \ + defined(TARGET_NR_recv) || defined(TARGET_NR_recvfrom) || \ + defined(TARGET_NR_recvmsg) || defined(TARGET_NR_send) || \ + defined(TARGET_NR_sendto) || defined(TARGET_NR_shutdown) || \ + defined(TARGET_NR_socketpair) + static long do_socketcallwrapper(int num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { @@ -1068,6 +1162,7 @@ return do_socketcall(num, (target_ulong) args); } +#endif #define N_SHM_REGIONS 32
_______________________________________________ Qemu-devel mailing list Qemu-devel@nongnu.org http://lists.nongnu.org/mailman/listinfo/qemu-devel