File: 21_net_soopts.patch

package info (click to toggle)
qemu 0.8.2-4etch3
  • links: PTS
  • area: main
  • in suites: etch
  • size: 8,404 kB
  • ctags: 27,580
  • sloc: ansic: 178,992; sh: 914; objc: 613; perl: 306; makefile: 287; asm: 152
file content (190 lines) | stat: -rw-r--r-- 5,873 bytes parent folder | download | duplicates (2)
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;