VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

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