The Network Kit: BNetPacket

Derived from: none

Declared in: be/addons/net_server/NetPacket.h

Library: libnetdev.so


Overview

Network packets are represented by objects derived from the BNetPacket pure virtual class. Your device or protocol add-on must implement a sub-class of BNetPacket that represents the packets your device or protocol manages. One derivation of BNetPacket, called BStandardPacket, is provided for you.

When a packet is received, the BNetDevice will allocate a new BNetPacket and fill it with the incoming packet data by using calls defined in this class. Likewise, when someone wants to send a packet, they'll call BNetDevice's AllocPacket() function to allocate an appropriate BNetPacket-derived object, then the functions described here to fill the packet with data.


Reading and Writing Packets

Once an object derived from BNetPacket is instantiated, data can be placed into the packet buffer by calling Write(), or by calling DataBlock() to get a pointer to the range of data the caller wants to change. Likewise, Read() is used to fetch data from the packet buffer, and DataBlock() returns a pointer so the buffer can be read directly.


Base and Size

An important component of your packet object is the buffer that actually contains the data in the packet. This buffer consists of a virtual block of memory--which doesn't have to be contiguous--and two values: base and size.

The base is the offset to the byte within the buffer that is currently considered to be the first byte of data in the buffer. This may sound like a strange concept, but it's actually a convenience--if you need to dodge headers and the like stashed in the data buffer, you can simply adjust the base offset. The offset into the buffer you specify when calling Read(), Write(), or DataBlock() is an offset from the current base.

The size is the number of bytes between the current base and the end of the packet buffer. That means that every time the base changes, the size changes as well, to reflect the new length of the data in the range from the base to the buffer's end.

There are two functions that you need to implement for each of these two values:

The SetBase() function you implement might look something like this:

   void MyNetPacket::SetBase(int offset) {
      base += offset;
      size -= offset;
   }

Your SetSize() function should do something like this:

   void MyNetPacket::SetSize(unsigned newsize) {
      ResizeBuffer(buffer, base+newsize);
      size = newsize; /* save the new size */
   }

This example assumes that the ResizeBuffer() function resizes the buffer to the size specified. The total size of the buffer should be the requested size plus the current base.

Obviously these examples skimp a bit on details; that's because the specifics depend largely on how your add-on works internally.


Constructor and Destructor


BNetPacket()


      BNetPacket(void)

Your derived class can implement the BNetPacket constructor, as desired.


~BNetPacket()


      virtual ~BNetPacket(void)

Your derived class can implement the BNetPacket destructor, as desired.


Member Functions


Base(), SetBase()


      virtual unsigned Base(void) = 0

      virtual void SetBase(int offset) = 0

Your derived class should implement Base() to return the offset into the packet at which data actually begins. The value returned by this function is an absolute offset into the packet data.

The SetBase() function should be implemented to set the base as an offset from the current base.

Together, these functions can be used to hide packet headers without actually stripping them out of the packets. Note that changing the base offset also should affect the value returned by Size(); if you add 15 to the base, you need to subtract 15 from the size to keep things in balance.


DataBlock()


      virtual char *DataBlock(unsigned offset, unsigned *size) = 0

Your derived class should implement this function to return a pointer to the byte of data located at the specified offset into the packet's data. Before calling DataBlock(), the caller has in the variable pointed to by size the number of bytes they'd like to read. Your implementation of DataBlock() should replace this with the actual number of bytes of data between offset+Base() and the end of the contiguous block. This value should only differ from the original value if there are fewer bytes remaining in the packet than the caller requests.

The offset should be added to the base offset specified by the last SetBase() call.

If the packet buffer is comprised of multiple non-contiguous blocks of memory, DataBlock() does not cross block boundaries. For example, if the buffer consists of three 1,000-byte buffers, and DataBlock() is called, with offset 500, requesting 1,000 bytes of data), only 500 bytes--the data between the offset 500 and the end of the first block--are returned. DataBlock() will have to be called multiple times to scan through all three blocks.

Your DataBlock() implementation should return NULL when the offset is at the end of the buffer. This indicates to the caller that there is no data left. You should never return 0 in size.

The data is not copied by this function; it only returns a pointer to the data and the number of bytes of data from the specified offset to the end of the contiguous block of data in which the specified offset resides.


Read(), Write()


      virtual void Read(unsigned offset, char *buffer, unsigned count) = 0

      virtual void Write(unsigned offset, const char *buffer, unsigned count) = 0

Your derived class should implement Read() to copy data from the specified offset in the packet's data to the address pointed to by buffer. Up to count bytes should be copied. If count is larger than the number of bytes between offset and the end of the packet, then that portion of the packet is transferred.

Write() should be implemented to write count bytes of data from the specified buffer to the specified offset in the packet data.

Default versions of Read() and Write() are provided for you; you probably won't have to implement them yourself.


SetSize(), Size()


      virtual void SetSize(unsigned size) = 0

      virtual unsigned Size(void) = 0

Your derived class should implement SetSize() to allow the caller to specify the size of the packet data that can be represented by the object. This size should be the size of the data following the current base offset, so if the current base is 32, you should set the size of the packet buffer to 32+size.

The Size() function should return the current packet size.

Note that the size of the packet buffer will fluctuate as the base offset is moved around using the SetBase() function. The Size() and SetSize() functions manipulate the size of the data between the current base and the end of the packet buffer.


Global C Functions


copy_packet()


      void copy_packet(BNetPacket *srcpacket, unsigned srcoffset, BNetPacket *dstpacket, unsigned dstoffset, unsigned size);

copy_packet() copies data from a source packet to a destination packet. size bytes of data are copied beginning at the specified srcoffset within the packet specified by srcpacket and stored starting at the specified dstoffset within the packet pointed to by the dstpacket parameter.






The Be Book, in lovely HTML, for BeOS Release 3.

Copyright © 1998 Be, Inc. All rights reserved.

Last modified March 26, 1998.