VirtualBox

source: vbox/trunk/include/VBox/intnetinline.h@ 27149

Last change on this file since 27149 was 26575, checked in by vboxsync, 15 years ago

build fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.4 KB
Line 
1/* $Id: intnetinline.h 26575 2010-02-16 12:51:22Z vboxsync $ */
2/** @file
3 * INTNET - Internal Networking, Inlined Code. (DEV,++)
4 *
5 * This is all inlined because it's too tedious to create 2-3 libraries to
6 * contain it all. Requires C++ since variables and code is mixed as usual.
7 */
8
9/*
10 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 *
20 * The contents of this file may alternatively be used under the terms
21 * of the Common Development and Distribution License Version 1.0
22 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
23 * VirtualBox OSE distribution, in which case the provisions of the
24 * CDDL are applicable instead of those of the GPL.
25 *
26 * You may elect to license modified versions of this file under the
27 * terms and conditions of either the GPL or the CDDL or both.
28 *
29 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
30 * Clara, CA 95054 USA or visit http://www.sun.com if you need
31 * additional information or have any questions.
32 */
33
34#ifndef ___VBox_intnetinline_h
35#define ___VBox_intnetinline_h
36
37#ifndef __cplusplus
38# error "C++ only header."
39#endif
40
41#include <VBox/intnet.h>
42#include <iprt/string.h>
43#include <iprt/assert.h>
44#include <iprt/err.h>
45#include <VBox/log.h>
46
47
48/**
49 * Get the amount of space available for writing.
50 *
51 * @returns Number of available bytes.
52 * @param pRingBuf The ring buffer.
53 */
54DECLINLINE(uint32_t) INTNETRingGetWritable(PINTNETRINGBUF pRingBuf)
55{
56 uint32_t const offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX);
57 uint32_t const offWriteInt = ASMAtomicUoReadU32(&pRingBuf->offWriteInt);
58 return offRead <= offWriteInt
59 ? pRingBuf->offEnd - offWriteInt + offRead - pRingBuf->offStart - 1
60 : offRead - offWriteInt - 1;
61}
62
63
64/**
65 * Checks if the ring has more for us to read.
66 *
67 * @returns Number of ready bytes.
68 * @param pRingBuf The ring buffer.
69 */
70DECLINLINE(bool) INTNETRingHasMoreToRead(PINTNETRINGBUF pRingBuf)
71{
72 uint32_t const offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX);
73 uint32_t const offWriteCom = ASMAtomicUoReadU32(&pRingBuf->offWriteCom);
74 return offRead != offWriteCom;
75}
76
77
78/**
79 * Gets the next frame to read.
80 *
81 * @returns Pointer to the next frame. NULL if done.
82 * @param pRingBuf The ring buffer.
83 */
84DECLINLINE(PINTNETHDR) INTNETRingGetNextFrameToRead(PINTNETRINGBUF pRingBuf)
85{
86 uint32_t const offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX);
87 uint32_t const offWriteCom = ASMAtomicUoReadU32(&pRingBuf->offWriteCom);
88 if (offRead == offWriteCom)
89 return NULL;
90 return (PINTNETHDR)((uint8_t *)pRingBuf + offRead);
91}
92
93
94/**
95 * Get the amount of data ready for reading.
96 *
97 * @returns Number of ready bytes.
98 * @param pRingBuf The ring buffer.
99 */
100DECLINLINE(uint32_t) INTNETRingGetReadable(PINTNETRINGBUF pRingBuf)
101{
102 uint32_t const offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX);
103 uint32_t const offWriteCom = ASMAtomicUoReadU32(&pRingBuf->offWriteCom);
104 return offRead <= offWriteCom
105 ? offWriteCom - offRead
106 : pRingBuf->offEnd - offRead + offWriteCom - pRingBuf->offStart;
107}
108
109
110/**
111 * Calculates the pointer to the frame.
112 *
113 * @returns Pointer to the start of the frame.
114 * @param pHdr Pointer to the packet header
115 * @param pBuf The buffer the header is within. Only used in strict builds.
116 */
117DECLINLINE(void *) INTNETHdrGetFramePtr(PCINTNETHDR pHdr, PCINTNETBUF pBuf)
118{
119 uint8_t *pu8 = (uint8_t *)pHdr + pHdr->offFrame;
120#ifdef VBOX_STRICT
121 const uintptr_t off = (uintptr_t)pu8 - (uintptr_t)pBuf;
122 Assert(pHdr->u16Type == INTNETHDR_TYPE_FRAME);
123 Assert(off < pBuf->cbBuf);
124 Assert(off + pHdr->cbFrame <= pBuf->cbBuf);
125#endif
126 NOREF(pBuf);
127 return pu8;
128}
129
130
131/**
132 * Skips to the next (read) frame in the buffer.
133 *
134 * @param pRingBuf The ring buffer in question.
135 */
136DECLINLINE(void) INTNETRingSkipFrame(PINTNETRINGBUF pRingBuf)
137{
138 uint32_t const offReadOld = ASMAtomicUoReadU32(&pRingBuf->offReadX);
139 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offReadOld);
140 Assert(offReadOld >= pRingBuf->offStart);
141 Assert(offReadOld < pRingBuf->offEnd);
142 Assert(RT_ALIGN_PT(pHdr, INTNETHDR_ALIGNMENT, INTNETHDR *) == pHdr);
143 Assert(pHdr->u16Type == INTNETHDR_TYPE_FRAME);
144
145 /* skip the frame */
146 uint32_t offReadNew = offReadOld + pHdr->offFrame + pHdr->cbFrame;
147 offReadNew = RT_ALIGN_32(offReadNew, INTNETHDR_ALIGNMENT);
148 Assert(offReadNew <= pRingBuf->offEnd && offReadNew >= pRingBuf->offStart);
149 if (offReadNew >= pRingBuf->offEnd)
150 offReadNew = pRingBuf->offStart;
151 Log2(("INTNETRingSkipFrame: offReadX: %#x -> %#x (1)\n", offReadOld, offReadNew));
152#ifdef INTNET_POISON_READ_FRAMES
153 memset((uint8_t *)pHdr + pHdr->offFrame, 0xfe, RT_ALIGN_32(pHdr->cbFrame, INTNETHDR_ALIGNMENT));
154 memset(pHdr, 0xef, sizeof(*pHdr));
155#endif
156 ASMAtomicWriteU32(&pRingBuf->offReadX, offReadNew);
157}
158
159
160/**
161 * Allocates a frame in the specified ring.
162 *
163 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW.
164 * @param pRingBuf The ring buffer.
165 * @param cbFrame The frame size.
166 * @param ppHdr Where to return the frame header.
167 * Don't touch this!
168 * @param ppvFrame Where to return the frame pointer.
169 */
170DECLINLINE(int) INTNETRingAllocateFrame(PINTNETRINGBUF pRingBuf, uint32_t cbFrame, PINTNETHDR *ppHdr, void **ppvFrame)
171{
172 /*
173 * Validate input and adjust the input.
174 */
175 INTNETRINGBUF_ASSERT_SANITY(pRingBuf);
176 Assert(cbFrame >= sizeof(RTMAC) * 2);
177
178 const uint32_t cb = RT_ALIGN_32(cbFrame, INTNETHDR_ALIGNMENT);
179 uint32_t offWriteInt = ASMAtomicUoReadU32(&pRingBuf->offWriteInt);
180 uint32_t offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX);
181 if (offRead <= offWriteInt)
182 {
183 /*
184 * Try fit it all before the end of the buffer.
185 */
186 if (pRingBuf->offEnd - offWriteInt >= cb + sizeof(INTNETHDR))
187 {
188 uint32_t offNew = offWriteInt + cb + sizeof(INTNETHDR);
189 if (offNew >= pRingBuf->offEnd)
190 offNew = pRingBuf->offStart;
191 if (RT_UNLIKELY(!ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt)))
192 return VERR_WRONG_ORDER; /* race */
193 Log2(("INTNETRingAllocateFrame: offWriteInt: %#x -> %#x (1) (offRead=%#x)\n", offWriteInt, offNew, offRead));
194
195 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt);
196 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
197 pHdr->cbFrame = (uint16_t)cbFrame; Assert(pHdr->cbFrame == cbFrame);
198 pHdr->offFrame = sizeof(INTNETHDR);
199
200 *ppHdr = pHdr;
201 *ppvFrame = pHdr + 1;
202 return VINF_SUCCESS;
203 }
204 /*
205 * Try fit the frame at the start of the buffer.
206 * (The header fits before the end of the buffer because of alignment.)
207 */
208 AssertMsg(pRingBuf->offEnd - offWriteInt >= sizeof(INTNETHDR), ("offEnd=%x offWriteInt=%x\n", pRingBuf->offEnd, offWriteInt));
209 if (offRead - pRingBuf->offStart > cb) /* not >= ! */
210 {
211 uint32_t offNew = pRingBuf->offStart + cb;
212 if (RT_UNLIKELY(!ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt)))
213 return VERR_WRONG_ORDER; /* race */
214 Log2(("INTNETRingAllocateFrame: offWriteInt: %#x -> %#x (2) (offRead=%#x)\n", offWriteInt, offNew, offRead));
215
216 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt);
217 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
218 pHdr->cbFrame = (uint16_t)cbFrame; Assert(pHdr->cbFrame == cbFrame);
219 pHdr->offFrame = pRingBuf->offStart - offWriteInt;
220
221 *ppHdr = pHdr;
222 *ppvFrame = (uint8_t *)pRingBuf + pRingBuf->offStart;
223 return VINF_SUCCESS;
224 }
225 }
226 /*
227 * The reader is ahead of the writer, try fit it into that space.
228 */
229 else if (offRead - offWriteInt > cb + sizeof(INTNETHDR)) /* not >= ! */
230 {
231 uint32_t offNew = offWriteInt + cb + sizeof(INTNETHDR);
232 if (RT_UNLIKELY(!ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt)))
233 return VERR_WRONG_ORDER; /* race */
234 Log2(("INTNETRingAllocateFrame: offWriteInt: %#x -> %#x (3) (offRead=%#x)\n", offWriteInt, offNew, offRead));
235
236 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt);
237 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
238 pHdr->cbFrame = (uint16_t)cbFrame; Assert(pHdr->cbFrame == cbFrame);
239 pHdr->offFrame = sizeof(INTNETHDR);
240
241 *ppHdr = pHdr;
242 *ppvFrame = pHdr + 1;
243 return VINF_SUCCESS;
244 }
245
246 /* (it didn't fit) */
247 STAM_REL_COUNTER_INC(&pRingBuf->cOverflows);
248 return VERR_BUFFER_OVERFLOW;
249}
250
251
252/**
253 * Commits a frame.
254 *
255 * Make sure to commit the frames in the order they've been allocated!
256 *
257 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW.
258 * @param pRingBuf The ring buffer.
259 * @param pHdr The frame header returned by
260 * INTNETRingAllocateFrame.
261 */
262DECLINLINE(void) INTNETRingCommitFrame(PINTNETRINGBUF pRingBuf, PINTNETHDR pHdr)
263{
264 /*
265 * Validate input and commit order.
266 */
267 INTNETRINGBUF_ASSERT_SANITY(pRingBuf);
268 INTNETHDR_ASSERT_SANITY(pHdr, pRingBuf);
269 Assert(pRingBuf->offWriteCom == ((uintptr_t)pHdr - (uintptr_t)pRingBuf));
270
271 /*
272 * Figure out the offWriteCom for this packet and update the ring.
273 */
274 const uint32_t cbFrame = pHdr->cbFrame;
275 const uint32_t cb = RT_ALIGN_32(cbFrame, INTNETHDR_ALIGNMENT);
276 uint32_t offWriteCom = (uint32_t)((uintptr_t)pHdr - (uintptr_t)pRingBuf)
277 + pHdr->offFrame
278 + cb;
279 if (offWriteCom >= pRingBuf->offEnd)
280 {
281 Assert(offWriteCom == pRingBuf->offEnd);
282 offWriteCom = pRingBuf->offStart;
283 }
284 Log2(("INTNETRingCommitFrame: offWriteCom: %#x -> %#x (offRead=%#x)\n", pRingBuf->offWriteCom, offWriteCom, pRingBuf->offReadX));
285 ASMAtomicWriteU32(&pRingBuf->offWriteCom, offWriteCom);
286 STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbFrame);
287 STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames);
288}
289
290
291/**
292 * Writes a frame to the specified ring.
293 *
294 * Make sure you don't have any uncommitted frames when calling this function!
295 *
296 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW.
297 * @param pRingBuf The ring buffer.
298 * @param pvFrame The bits to write.
299 * @param cbFrame How much to write.
300 */
301DECLINLINE(int) INTNETRingWriteFrame(PINTNETRINGBUF pRingBuf, const void *pvFrame, size_t cbFrame)
302{
303 /*
304 * Validate input.
305 */
306 INTNETRINGBUF_ASSERT_SANITY(pRingBuf);
307 Assert(cbFrame >= sizeof(RTMAC) * 2);
308
309 /*
310 * Align the size and read the volatile ring buffer variables.
311 */
312 const uint32_t cb = RT_ALIGN_32(cbFrame, INTNETHDR_ALIGNMENT);
313 uint32_t offWriteInt = ASMAtomicUoReadU32(&pRingBuf->offWriteInt);
314 uint32_t offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX);
315 if (offRead <= offWriteInt)
316 {
317 /*
318 * Try fit it all before the end of the buffer.
319 */
320 if (pRingBuf->offEnd - offWriteInt >= cb + sizeof(INTNETHDR))
321 {
322 uint32_t offNew = offWriteInt + cb + sizeof(INTNETHDR);
323 if (offNew >= pRingBuf->offEnd)
324 offNew = pRingBuf->offStart;
325 if (RT_UNLIKELY(!ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt)))
326 return VERR_WRONG_ORDER; /* race */
327 Log2(("INTNETRingWriteFrame: offWriteInt: %#x -> %#x (1)\n", offWriteInt, offNew));
328
329 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt);
330 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
331 pHdr->cbFrame = (uint16_t)cbFrame; Assert(pHdr->cbFrame == cbFrame);
332 pHdr->offFrame = sizeof(INTNETHDR);
333
334 memcpy(pHdr + 1, pvFrame, cbFrame);
335
336 Log2(("INTNETRingWriteFrame: offWriteCom: %#x -> %#x (1)\n", pRingBuf->offWriteCom, offNew));
337 ASMAtomicWriteU32(&pRingBuf->offWriteCom, offNew);
338 STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbFrame);
339 STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames);
340 return VINF_SUCCESS;
341 }
342 /*
343 * Try fit the frame at the start of the buffer.
344 * (The header fits before the end of the buffer because of alignment.)
345 */
346 AssertMsg(pRingBuf->offEnd - offWriteInt >= sizeof(INTNETHDR), ("offEnd=%x offWriteInt=%x\n", pRingBuf->offEnd, offWriteInt));
347 if (offRead - pRingBuf->offStart > cb) /* not >= ! */
348 {
349 uint32_t offNew = pRingBuf->offStart + cb;
350 if (RT_UNLIKELY(!ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt)))
351 return VERR_WRONG_ORDER; /* race */
352 Log2(("INTNETRingWriteFrame: offWriteInt: %#x -> %#x (2)\n", offWriteInt, offNew));
353
354 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt);
355 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
356 pHdr->cbFrame = (uint16_t)cbFrame; Assert(pHdr->cbFrame == cbFrame);
357 pHdr->offFrame = pRingBuf->offStart - offWriteInt;
358
359 memcpy((uint8_t *)pRingBuf + pRingBuf->offStart, pvFrame, cbFrame);
360
361 Log2(("INTNETRingWriteFrame: offWriteCom: %#x -> %#x (2)\n", pRingBuf->offWriteCom, offNew));
362 ASMAtomicWriteU32(&pRingBuf->offWriteCom, offNew);
363 STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbFrame);
364 STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames);
365 return VINF_SUCCESS;
366 }
367 }
368 /*
369 * The reader is ahead of the writer, try fit it into that space.
370 */
371 else if (offRead - offWriteInt > cb + sizeof(INTNETHDR)) /* not >= ! */
372 {
373 uint32_t offNew = offWriteInt + cb + sizeof(INTNETHDR);
374 if (RT_UNLIKELY(!ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt)))
375 return VERR_WRONG_ORDER; /* race */
376 Log2(("INTNETRingWriteFrame: offWriteInt: %#x -> %#x (3)\n", offWriteInt, offNew));
377
378 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt);
379 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
380 pHdr->cbFrame = (uint16_t)cbFrame; Assert(pHdr->cbFrame == cbFrame);
381 pHdr->offFrame = sizeof(INTNETHDR);
382
383 memcpy(pHdr + 1, pvFrame, cbFrame);
384
385 Log2(("INTNETRingWriteFrame: offWriteCom: %#x -> %#x (3)\n", pRingBuf->offWriteCom, offNew));
386 ASMAtomicWriteU32(&pRingBuf->offWriteCom, offNew);
387 STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbFrame);
388 STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames);
389 return VINF_SUCCESS;
390 }
391
392 /* (it didn't fit) */
393 STAM_REL_COUNTER_INC(&pRingBuf->cOverflows);
394 return VERR_BUFFER_OVERFLOW;
395}
396
397
398/**
399 * Reads the next frame in the buffer and moves the read cursor past it.
400 *
401 * @returns Size of the frame in bytes. 0 is returned if nothing in the buffer.
402 * @param pRingBuff The ring buffer to read from.
403 * @param pvFrameDst Where to put the frame. The caller is responsible for
404 * ensuring that there is sufficient space for the frame.
405 *
406 * @deprecated Bad interface, do NOT use it! Only for tstIntNetR0.
407 */
408DECLINLINE(uint32_t) INTNETRingReadAndSkipFrame(PINTNETRINGBUF pRingBuf, void *pvFrameDst)
409{
410 INTNETRINGBUF_ASSERT_SANITY(pRingBuf);
411
412 uint32_t offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX);
413 uint32_t const offWriteCom = ASMAtomicUoReadU32(&pRingBuf->offWriteCom);
414 if (offRead == offWriteCom)
415 return 0;
416
417 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offRead);
418 INTNETHDR_ASSERT_SANITY(pHdr, pRingBuf);
419
420 uint32_t const cbFrame = pHdr->cbFrame;
421 int32_t const offFrame = pHdr->offFrame;
422 const void *pvFrameSrc = (uint8_t *)pHdr + offFrame;
423 memcpy(pvFrameDst, pvFrameSrc, cbFrame);
424#ifdef INTNET_POISON_READ_FRAMES
425 memset((void *)pvFrameSrc, 0xfe, RT_ALIGN_32(cbFrame, INTNETHDR_ALIGNMENT));
426 memset(pHdr, 0xef, sizeof(*pHdr));
427#endif
428
429 /* skip the frame */
430 offRead += offFrame + cbFrame;
431 offRead = RT_ALIGN_32(offRead, INTNETHDR_ALIGNMENT);
432 Assert(offRead <= pRingBuf->offEnd && offRead >= pRingBuf->offStart);
433 if (offRead >= pRingBuf->offEnd)
434 offRead = pRingBuf->offStart;
435 ASMAtomicWriteU32(&pRingBuf->offReadX, offRead);
436 return cbFrame;
437}
438
439
440
441/**
442 * Initializes a buffer structure.
443 *
444 * @param pIntBuf The internal networking interface buffer. This
445 * expected to be cleared prior to calling this
446 * function.
447 * @param cbBuf The size of the whole buffer.
448 * @param cbRecv The receive size.
449 * @param cbSend The send size.
450 */
451DECLINLINE(void) INTNETBufInit(PINTNETBUF pIntBuf, uint32_t cbBuf, uint32_t cbRecv, uint32_t cbSend)
452{
453 AssertCompileSizeAlignment(INTNETBUF, INTNETHDR_ALIGNMENT);
454 AssertCompileSizeAlignment(INTNETBUF, INTNETRINGBUF_ALIGNMENT);
455 Assert(cbBuf >= sizeof(INTNETBUF) + cbRecv + cbSend);
456 Assert(RT_ALIGN_32(cbRecv, INTNETRINGBUF_ALIGNMENT) == cbRecv);
457 Assert(RT_ALIGN_32(cbSend, INTNETRINGBUF_ALIGNMENT) == cbSend);
458 Assert(ASMMemIsAll8(pIntBuf, cbBuf, '\0') == NULL);
459
460 pIntBuf->u32Magic = INTNETBUF_MAGIC;
461 pIntBuf->cbBuf = cbBuf;
462 pIntBuf->cbRecv = cbRecv;
463 pIntBuf->cbSend = cbSend;
464
465 /* receive ring buffer. */
466 uint32_t offBuf = RT_ALIGN_32(sizeof(INTNETBUF), INTNETRINGBUF_ALIGNMENT) - RT_OFFSETOF(INTNETBUF, Recv);
467 pIntBuf->Recv.offStart = offBuf;
468 pIntBuf->Recv.offReadX = offBuf;
469 pIntBuf->Recv.offWriteInt = offBuf;
470 pIntBuf->Recv.offWriteCom = offBuf;
471 pIntBuf->Recv.offEnd = offBuf + cbRecv;
472
473 /* send ring buffer. */
474 offBuf += cbRecv + RT_OFFSETOF(INTNETBUF, Recv) - RT_OFFSETOF(INTNETBUF, Send);
475 pIntBuf->Send.offStart = offBuf;
476 pIntBuf->Send.offReadX = offBuf;
477 pIntBuf->Send.offWriteCom = offBuf;
478 pIntBuf->Send.offWriteInt = offBuf;
479 pIntBuf->Send.offEnd = offBuf + cbSend;
480 Assert(cbBuf >= offBuf + cbSend);
481}
482
483#endif
484
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