VirtualBox

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

Last change on this file since 76747 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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