VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/sbuf.c@ 28520

Last change on this file since 28520 was 28510, checked in by vboxsync, 15 years ago

refined r60215

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.5 KB
Line 
1/* $Id: sbuf.c 28510 2010-04-20 10:25:22Z vboxsync $ */
2/** @file
3 * NAT - sbuf implemenation.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*
23 * This code is based on:
24 *
25 * Copyright (c) 1995 Danny Gasparovski.
26 *
27 * Please read the file COPYRIGHT for the
28 * terms and conditions of the copyright.
29 */
30
31#include <slirp.h>
32
33/* Done as a macro in socket.h */
34/* int
35 * sbspace(struct sockbuff *sb)
36 * {
37 * return SB_DATALEN - sb->sb_cc;
38 * }
39 */
40
41void
42sbfree(struct sbuf *sb)
43{
44 /*
45 * Catch double frees. Actually tcp_close() already filters out listening sockets
46 * passing NULL.
47 */
48 Assert((sb->sb_data));
49
50 /*
51 * Don't call RTMemFree() for an already freed buffer, the EFence could complain
52 */
53 if (sb->sb_data)
54 {
55 RTMemFree(sb->sb_data);
56 sb->sb_data = NULL;
57 }
58}
59
60void
61sbdrop(struct sbuf *sb, int num)
62{
63 /*
64 * We can only drop how much we have
65 * This should never succeed
66 */
67 if (num > sb->sb_cc)
68 num = sb->sb_cc;
69 sb->sb_cc -= num;
70 sb->sb_rptr += num;
71 if (sb->sb_rptr >= sb->sb_data + sb->sb_datalen)
72 sb->sb_rptr -= sb->sb_datalen;
73
74}
75
76void
77sbreserve(PNATState pData, struct sbuf *sb, int size)
78{
79 if (sb->sb_data)
80 {
81 /* Already alloced, realloc if necessary */
82 if (sb->sb_datalen != size)
83 {
84 sb->sb_wptr =
85 sb->sb_rptr =
86 sb->sb_data = (char *)RTMemRealloc(sb->sb_data, size);
87 sb->sb_cc = 0;
88 if (sb->sb_wptr)
89 sb->sb_datalen = size;
90 else
91 sb->sb_datalen = 0;
92 }
93 }
94 else
95 {
96 sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)RTMemAlloc(size);
97 sb->sb_cc = 0;
98 if (sb->sb_wptr)
99 sb->sb_datalen = size;
100 else
101 sb->sb_datalen = 0;
102 }
103}
104
105/*
106 * Try and write() to the socket, whatever doesn't get written
107 * append to the buffer... for a host with a fast net connection,
108 * this prevents an unnecessary copy of the data
109 * (the socket is non-blocking, so we won't hang)
110 */
111void
112sbappend(PNATState pData, struct socket *so, struct mbuf *m)
113{
114 int ret = 0;
115#ifdef VBOX_WITH_SLIRP_BSD_MBUF
116 int mlen = 0;
117 caddr_t buf = NULL;
118#endif
119
120 STAM_PROFILE_START(&pData->StatIOSBAppend_pf, a);
121 DEBUG_CALL("sbappend");
122 DEBUG_ARG("so = %lx", (long)so);
123 DEBUG_ARG("m = %lx", (long)m);
124 DEBUG_ARG("m->m_len = %d", m ? m->m_len : 0);
125
126 STAM_COUNTER_INC(&pData->StatIOSBAppend);
127 /* Shouldn't happen, but... e.g. foreign host closes connection */
128#ifndef VBOX_WITH_SLIRP_BSD_MBUF
129 if (m->m_len <= 0)
130#else
131 mlen = m_length(m, NULL);
132 if (mlen <= 0)
133#endif
134 {
135 STAM_COUNTER_INC(&pData->StatIOSBAppend_zm);
136 goto done;
137 }
138
139 /*
140 * If there is urgent data, call sosendoob
141 * if not all was sent, sowrite will take care of the rest
142 * (The rest of this function is just an optimisation)
143 */
144 if (so->so_urgc)
145 {
146 sbappendsb(pData, &so->so_rcv, m);
147 m_free(pData, m);
148 sosendoob(so);
149 return;
150 }
151
152 /*
153 * We only write if there's nothing in the buffer,
154 * ottherwise it'll arrive out of order, and hence corrupt
155 */
156#ifndef VBOX_WITH_SLIRP_BSD_MBUF
157 if(!so->so_rcv.sb_cc)
158 ret = send(so->s, m->m_data, m->m_len, 0);
159#else
160 buf = RTMemAlloc(mlen);
161 if (buf == NULL)
162 {
163 ret = 0;
164 goto no_sent;
165 }
166 m_copydata(m, 0, mlen, buf);
167 if(!so->so_rcv.sb_cc)
168 ret = send(so->s, buf, mlen, 0);
169 RTMemFree(buf);
170no_sent:
171#endif
172
173 if (ret <= 0)
174 {
175 STAM_COUNTER_INC(&pData->StatIOSBAppend_wf);
176 /*
177 * Nothing was written
178 * It's possible that the socket has closed, but
179 * we don't need to check because if it has closed,
180 * it will be detected in the normal way by soread()
181 */
182 sbappendsb(pData, &so->so_rcv, m);
183 STAM_PROFILE_STOP(&pData->StatIOSBAppend_pf_wf, a);
184 goto done;
185 }
186#ifndef VBOX_WITH_SLIRP_BSD_MBUF
187 else if (ret != m->m_len)
188#else
189 else if (ret != mlen)
190#endif
191 {
192 STAM_COUNTER_INC(&pData->StatIOSBAppend_wp);
193 /*
194 * Something was written, but not everything..
195 * sbappendsb the rest
196 */
197#ifndef VBOX_WITH_SLIRP_BSD_MBUF
198 m->m_len -= ret;
199 m->m_data += ret;
200#else
201 m_adj(m, ret);
202#endif
203 sbappendsb(pData, &so->so_rcv, m);
204 STAM_PROFILE_STOP(&pData->StatIOSBAppend_pf_wp, a);
205 goto done;
206 } /* else */
207 /* Whatever happened, we free the mbuf */
208 STAM_COUNTER_INC(&pData->StatIOSBAppend_wa);
209 STAM_PROFILE_STOP(&pData->StatIOSBAppend_pf_wa, a);
210done:
211 m_free(pData, m);
212}
213
214/*
215 * Copy the data from m into sb
216 * The caller is responsible to make sure there's enough room
217 */
218void
219sbappendsb(PNATState pData, struct sbuf *sb, struct mbuf *m)
220{
221 int len, n, nn;
222
223#ifndef VBOX_WITH_SLIRP_BSD_MBUF
224 len = m->m_len;
225#else
226 len = m_length(m, NULL);
227#endif
228
229 STAM_COUNTER_INC(&pData->StatIOSBAppendSB);
230 if (sb->sb_wptr < sb->sb_rptr)
231 {
232 STAM_COUNTER_INC(&pData->StatIOSBAppendSB_w_l_r);
233 n = sb->sb_rptr - sb->sb_wptr;
234 if (n > len)
235 n = len;
236#ifndef VBOX_WITH_SLIRP_BSD_MBUF
237 memcpy(sb->sb_wptr, m->m_data, n);
238#else
239 m_copydata(m, 0, n, sb->sb_wptr);
240#endif
241 }
242 else
243 {
244 STAM_COUNTER_INC(&pData->StatIOSBAppendSB_w_ge_r);
245 /* Do the right edge first */
246 n = sb->sb_data + sb->sb_datalen - sb->sb_wptr;
247 if (n > len)
248 n = len;
249#ifndef VBOX_WITH_SLIRP_BSD_MBUF
250 memcpy(sb->sb_wptr, m->m_data, n);
251#else
252 m_copydata(m, 0, n, sb->sb_wptr);
253#endif
254 len -= n;
255 if (len)
256 {
257 /* Now the left edge */
258 nn = sb->sb_rptr - sb->sb_data;
259 if (nn > len)
260 nn = len;
261#ifndef VBOX_WITH_SLIRP_BSD_MBUF
262 memcpy(sb->sb_data, m->m_data+n, nn);
263#else
264 m_copydata(m, n, nn, sb->sb_wptr);
265#endif
266 n += nn;
267 }
268 }
269
270 sb->sb_cc += n;
271 sb->sb_wptr += n;
272 if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen)
273 {
274 STAM_COUNTER_INC(&pData->StatIOSBAppendSB_w_alter);
275 sb->sb_wptr -= sb->sb_datalen;
276 }
277}
278
279/*
280 * Copy data from sbuf to a normal, straight buffer
281 * Don't update the sbuf rptr, this will be
282 * done in sbdrop when the data is acked
283 */
284void
285sbcopy(struct sbuf *sb, int off, int len, char *to)
286{
287 char *from;
288
289 from = sb->sb_rptr + off;
290 if (from >= sb->sb_data + sb->sb_datalen)
291 from -= sb->sb_datalen;
292
293 if (from < sb->sb_wptr)
294 {
295 if (len > sb->sb_cc)
296 len = sb->sb_cc;
297 memcpy(to, from, len);
298 }
299 else
300 {
301 /* re-use off */
302 off = (sb->sb_data + sb->sb_datalen) - from;
303 if (off > len)
304 off = len;
305 memcpy(to, from, off);
306 len -= off;
307 if (len)
308 memcpy(to+off, sb->sb_data, len);
309 }
310}
311
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette