1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
Index: linux-user/syscall.c
===================================================================
--- linux-user/syscall.c.orig 2006-07-22 20:23:34.000000000 +0300
+++ linux-user/syscall.c 2006-10-05 21:22:44.000000000 +0300
@@ -509,6 +509,28 @@ static inline void host_to_target_cmsg(s
msgh->msg_controllen = tswapl(space);
}
+static inline void host_to_target_linger(target_ulong target_addr,
+ struct linger *host_l)
+{
+ struct target_linger *target_l;
+
+ lock_user_struct(target_l, target_addr, 0);
+ target_l->l_onoff = tswapl(host_l->l_onoff);
+ target_l->l_linger = tswapl(host_l->l_linger);
+ unlock_user_struct(target_l, target_addr, 1);
+}
+
+static inline void target_to_host_linger(struct linger *host_l,
+ target_ulong target_addr)
+{
+ struct target_linger *target_l;
+
+ lock_user_struct(target_l, target_addr, 1);
+ host_l->l_onoff = tswapl(target_l->l_onoff);
+ host_l->l_linger = tswapl(target_l->l_linger);
+ unlock_user_struct(target_l, target_addr, 0);
+}
+
static long do_setsockopt(int sockfd, int level, int optname,
target_ulong optval, socklen_t optlen)
{
@@ -554,7 +576,6 @@ static long do_setsockopt(int sockfd, in
break;
case TARGET_SOL_SOCKET:
switch (optname) {
- /* Options with 'int' argument. */
case TARGET_SO_DEBUG:
optname = SO_DEBUG;
break;
@@ -611,16 +632,46 @@ static long do_setsockopt(int sockfd, in
case TARGET_SO_SNDTIMEO:
optname = SO_SNDTIMEO;
break;
- break;
+ case TARGET_SO_LINGER:
+ optname = SO_LINGER;
+ 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)));
- break;
+ switch (optname) {
+ /* Options with non-'int' argument. */
+ case SO_RCVTIMEO:
+ case SO_SNDTIMEO:
+ {
+ struct timeval tval;
+ if(optlen < sizeof(struct target_timeval))
+ return -EINVAL;
+ target_to_host_timeval(&tval,optval);
+ ret = get_errno(setsockopt(sockfd, level, optname, &tval,sizeof(tval)));
+ }
+ break;
+ case SO_LINGER:
+ {
+ struct linger tmp;
+ if (optlen < sizeof(struct target_linger))
+ return -EINVAL;
+ optname = SO_LINGER;
+ target_to_host_linger(&tmp,optval);
+ ret = get_errno(setsockopt(sockfd, level, optname, &tmp, sizeof(tmp)));
+ }
+ break;
+ /* All remaning options take an 'int' argument. */
+ default:
+ {
+ if (optlen < sizeof(uint32_t))
+ return -EINVAL;
+
+ val = tget32(optval);
+ ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
+ }
+ break;
+ }
default:
unimplemented:
gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
@@ -638,13 +689,50 @@ static long do_getsockopt(int sockfd, in
case TARGET_SOL_SOCKET:
level = SOL_SOCKET;
switch (optname) {
- case TARGET_SO_LINGER:
+ case TARGET_SO_LINGER: {
+ len=tget32(optlen);
+ if(len < sizeof(struct target_linger))
+ return -EINVAL;
+ struct linger l;
+ len=sizeof(l);
+
+ ret = get_errno(getsockopt(sockfd, level, optname, &l, &len));
+ host_to_target_linger(optval,&l);
+ tput32(optlen, sizeof(struct target_linger));
+ }
+ break;
+
case TARGET_SO_RCVTIMEO:
- case TARGET_SO_SNDTIMEO:
- case TARGET_SO_PEERCRED:
+ case TARGET_SO_SNDTIMEO: {
+ len=tget32(optlen);
+ if(len < sizeof(struct target_timeval))
+ return -EINVAL;
+ struct timeval tval;
+ len=sizeof(tval);
+
+ ret = get_errno(getsockopt(sockfd, level, optname, &tval, &len));
+ host_to_target_timeval(optval,&tval);
+ tput32(optlen, sizeof(struct target_timeval));
+ }
+ break;
+
case TARGET_SO_PEERNAME:
/* These don't just return a single integer */
goto unimplemented;
+ case TARGET_SO_PEERCRED: {
+ struct ucred caller;
+ socklen_t optlen = sizeof (caller);
+ ret = get_errno(getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED,
+ &caller, &optlen));
+
+ if (optlen != 0 && optval != 0) {
+ tput32(optval + 0, caller.pid);
+ tput32(optval + 4, caller.uid);
+ tput32(optval + 8, caller.gid);
+ }
+ }
+ break;
+
default:
goto int_case;
}
@@ -878,12 +966,23 @@ static long do_socketcall(int num, targe
int sockfd = tgetl(vptr);
target_ulong target_addr = tgetl(vptr + n);
target_ulong target_addrlen = tgetl(vptr + 2 * n);
- socklen_t addrlen = tget32(target_addrlen);
- void *addr = alloca(addrlen);
+ socklen_t addrlen;
+ void *addr = NULL;
+ if (target_addrlen != (target_ulong)NULL &&
+ target_addr != (target_ulong)NULL) {
+ addrlen = tget32(target_addrlen);
+ addr = alloca(addrlen);
ret = get_errno(accept(sockfd, addr, &addrlen));
+ } else {
+ ret = get_errno(accept(sockfd, NULL, NULL));
+ break;
+ }
+
if (!is_error(ret)) {
+ if (target_addr != (target_ulong)NULL)
host_to_target_sockaddr(target_addr, addr, addrlen);
+ if (target_addrlen != (target_ulong)NULL)
tput32(target_addrlen, addrlen);
}
}
Index: linux-user/syscall_defs.h
===================================================================
--- linux-user/syscall_defs.h.orig 2006-07-22 20:23:34.000000000 +0300
+++ linux-user/syscall_defs.h 2006-10-05 21:01:15.000000000 +0300
@@ -113,6 +113,11 @@ struct target_timespec {
target_long tv_nsec;
};
+struct target_linger {
+ target_long l_onoff;
+ target_long l_linger;
+};
+
struct target_itimerval {
struct target_timeval it_interval;
struct target_timeval it_value;
|