The "UDPpacket" structure "data" member type

Hello,

I am using sdl_net-1.2.8.
I have a problem with the “UDPpacket” structure [1] because the “data” member is of type “Uint8*” whereas the data I want to send over network is a structure… So I am unable to cast.

Why it is not a “void*” type for the data member ?

Thank you.
Best regards.

[1] http://jcatki.no-ip.org:8080/SDL_net/SDL_net.html#SEC52

2013/10/6 YuGiOhJCJ Mailing-List

Hello,

I am using sdl_net-1.2.8.
I have a problem with the “UDPpacket” structure [1] because the "data"
member is of type “Uint8*” whereas the data I want to send over network is
a structure… So I am unable to cast.

Why it is not a “void*” type for the data member ?

Thank you.
Best regards.

Hi,

I presume you’re using C++? If everything else fails you can always
reinterpret_cast anything to anything
(I think). Anyway, I’m not sure you’re just supposed to point the packet’s
data pointer to your structure.
When you create the UDP packet, you specify a size, right? I think the data
member points to an already
allocated chunk of memory, so you should just memcpy your struct into it
(assuming you allocated the
packet with the size of your struct).

Jonas

In fact, I am using the C language, not the C++ language.
So, I have not access to reinterpret_cast.

Yes, I specify a size for the packet :—
// Create the packet
UDPpacket *packet = NULL;
packet = SDLNet_AllocPacket(1024);

But this size of 1024 is not the same than the one in “packet->len”:

packet->len = 6;

Anyway, below is a source code that is working for a string.
Now, I would like to send a structure instead of this string.
For example, we can take this structure:
data.h :
typedef struct data
{
int integer;
char str[6];
} data_t;

Finally, I found the way how to cast correctly:

data_t data;
strcpy(data.str, “Hello\0”);
data.integer = 123;
packet->data = (Uint8*)&data;
packet->len = sizeof(data);

The data is correctly sent and received between the server and the client.

Problem solved.

server.c:
#include <stdio.h> /* for printf /
#include <stdlib.h> /
for exit /
#include <SDL/SDL.h> /
for SDL_Init /
#include <SDL/SDL_net.h> /
for SDLNet_Init /
#include <unistd.h> /
for sleep */
int main()
{
// Initialize
if(SDL_Init(0) == -1)
{
printf(“SDL_Init: %s\n”, SDL_GetError());
exit(EXIT_FAILURE);
}
if(SDLNet_Init() == -1) {
printf(“SDLNet_Init: %s\n”, SDLNet_GetError());
exit(EXIT_FAILURE);
}
// Create the socket
UDPsocket udpsock = NULL;
udpsock = SDLNet_UDP_Open(6666);
if(udpsock == NULL)
{
printf(“SDLNet_UDP_Open: %s\n”, SDLNet_GetError());
exit(EXIT_FAILURE);
}
// Create the packet
UDPpacket *packet = NULL;
packet = SDLNet_AllocPacket(1024);
if(packet == NULL)
{
printf(“SDLNet_AllocPacket: %s\n”, SDLNet_GetError());
exit(EXIT_FAILURE);
}
// Receive the packet
int numrecv;
while(1)
{
numrecv = SDLNet_UDP_Recv(udpsock, packet);
printf(“numrecv = %d (packet->data = “%s”)\n”, numrecv, (char *) packet->data);
sleep(1);
}
SDLNet_FreePacket(packet);
SDLNet_Quit();
SDL_Quit();
exit(EXIT_SUCCESS);
}

client.c:
#include <stdio.h> /* for printf /
#include <stdlib.h> /
for exit /
#include <SDL/SDL.h> /
for SDL_Init /
#include <SDL/SDL_net.h> /
for SDLNet_Init /
#include <unistd.h> /
for sleep */
int main()
{
char data[6] = “Hello\0”;
// Initialize
if(SDL_Init(0) == -1)
{
printf(“SDL_Init: %s\n”, SDL_GetError());
exit(EXIT_FAILURE);
}
if(SDLNet_Init() == -1) {
printf(“SDLNet_Init: %s\n”, SDLNet_GetError());
exit(EXIT_FAILURE);
}
// Create the socket
UDPsocket udpsock;
udpsock = SDLNet_UDP_Open(0);
if(!udpsock)
{
printf(“SDLNet_UDP_Open: %s\n”, SDLNet_GetError());
exit(1);
}
// Resolve host
IPaddress ipaddress;
if(SDLNet_ResolveHost(&ipaddress, “localhost”, 6666) == -1)
{
printf(“SDLNet_ResolveHost: %s\n”, SDLNet_GetError());
exit(EXIT_FAILURE);
}
// Create the packet
UDPpacket *packet = NULL;
packet = SDLNet_AllocPacket(1024);
if(packet == NULL)
{
printf(“SDLNet_AllocPacket: %s\n”, SDLNet_GetError());
exit(EXIT_FAILURE);
}
packet->data = data;
packet->len = 6;
packet->address = ipaddress;
// Send the packet
int numsent;
while(1)
{
numsent = SDLNet_UDP_Send(udpsock, packet->channel, packet);
printf(“numsent = %d (packet->data = “%s”)\n”, numsent, (char *)packet->data);
sleep(1);
}
SDLNet_FreePacket(packet);
SDLNet_Quit();
SDL_Quit();
exit(EXIT_SUCCESS);
}

On Sun, 6 Oct 2013 17:04:41 +0200 Jonas Kulla wrote:

2013/10/6 YuGiOhJCJ Mailing-List <@YuGiOhJCJ_Mailing-Li>

Hello,

I am using sdl_net-1.2.8.
I have a problem with the “UDPpacket” structure [1] because the "data"
member is of type “Uint8*” whereas the data I want to send over network is
a structure… So I am unable to cast.

Why it is not a “void*” type for the data member ?

Thank you.
Best regards.

Hi,

I presume you’re using C++? If everything else fails you can always
reinterpret_cast anything to anything
(I think). Anyway, I’m not sure you’re just supposed to point the packet’s
data pointer to your structure.
When you create the UDP packet, you specify a size, right? I think the data
member points to an already
allocated chunk of memory, so you should just memcpy your struct into it
(assuming you allocated the
packet with the size of your struct).

Jonas

2013/10/6 YuGiOhJCJ Mailing-List

In fact, I am using the C language, not the C++ language.
So, I have not access to reinterpret_cast.

Yes, I specify a size for the packet :

// Create the packet
UDPpacket *packet = NULL;
packet = SDLNet_AllocPacket(1024);

But this size of 1024 is not the same than the one in “packet->len”:

packet->len = 6;

Anyway, below is a source code that is working for a string.
Now, I would like to send a structure instead of this string.
For example, we can take this structure:
data.h :
typedef struct data
{
int integer;
char str[6];
} data_t;

Finally, I found the way how to cast correctly:

data_t data;
strcpy(data.str, “Hello\0”);
data.integer = 123;
packet->data = (Uint8*)&data;
packet->len = sizeof(data);

The data is correctly sent and received between the server and the client.

Problem solved.

Uhh, I have a feeling you’re just leaking memory here. Have you tried doing
this instead?

packet = SDL_NetAllocPacket(sizeof(data_t));
memcpy(packet->data, &data;

2013/10/6 Jonas Kulla <@Jonas_Kulla>

Uhh, I have a feeling you’re just leaking memory here. Have you tried
doing this instead?

packet = SDL_NetAllocPacket(sizeof(data_t));
memcpy(packet->data, &data;

I’m kinda sleepy, this is what it should have been:

packet = SDL_NetAllocPacket(sizeof(data));
memcpy(packet->data, &data, sizeof(data));
packet->len = sizeof(data);

Mightn’t that fail if the machine the data is sent to happens to use
a different structure packing arrangement, uses a 64 bit integer, or
any number of things?

When it comes to on disk and over the network formats, my preference
is always to allocate as much data as I need as bytes, then
explicitly copy that data over as tightly packed data of a specific
size and endianness.

Something like:

typedef struct data {
    int integer; /* 32 bit or larger */
    char str[6];
} data_t;
#define NETWORK_DATA_SIZE 10

?

packet = SDL_NetAllocPacket(NETWORK_DATA_SIZE);
*(int *)(packet->data + 0) = SDL_SwapLE32((Uint32)data.integer);
SDL_memcpy(packet->data + 4, data.str, 6);

Something like that.

Actually my implementation of such things is slightly more complex
than this, but a lot cleaner. Structures that are read/written to
disk or network all come with either a raw data packet size, or can
have it quickly calculated via macro. I then set a generic pointer
to the start of the buffer and use force-inlined functions to do the
ugly bit. So it’d look like:

p = packet->data;
Raw_WriteSint32(&p, data.integer);
Raw_WriteData(&p, data.str, sizeof(data.str));

Actually, if I were dealing with an arbitrary string that could be
significantly longer than 6 characters, I’d use my Raw_WritePStr
function, which uses a kind of Pascal-ish C string. Basically, a C
string prefixed by a Uint16 length (null-inclusive). When working
with an arbitrary stream, I figure the two extra bytes are worth
being able to simply Raw_ReadUint16, then malloc, memcpy, and advance
the pointer by the amount indicated. :slight_smile:

To read it back:

p = packet->data;
data.integer = Raw_ReadSint32(&p);
Raw_ReadData(&p, &data.str), sizeof(data.str));

Probably not the most efficient way to do it, since you can usually
convinced the compiler to give you a packed structure. Except that
some processors genuinely can’t access things larger than bytes that
aren’t properly aligned, so you may not actually be able to suggest
that the compiler do what you want.

Of course I’d be open to someone suggesting I’m also doing it wrong
if they have a better idea. :slight_smile:

JosephOn Sun, Oct 06, 2013 at 06:31:36PM +0200, Jonas Kulla wrote:

2013/10/6 Jonas Kulla

Uhh, I have a feeling you’re just leaking memory here. Have you tried
doing this instead?

packet = SDL_NetAllocPacket(sizeof(data_t));
memcpy(packet->data, &data;

I’m kinda sleepy, this is what it should have been:

packet = SDL_NetAllocPacket(sizeof(data));
memcpy(packet->data, &data, sizeof(data));
packet->len = sizeof(data);

Message-ID: <20131006162705.2688980931ab9fc1818ac56f at laposte.net>
Content-Type: text/plain; charset=US-ASCII

Hello,

I am using sdl_net-1.2.8.
I have a problem with the “UDPpacket” structure [1] because the "data"
member is of type “Uint8*” whereas the data I want to send over network is a
structure… So I am unable to cast.

Why it is not a “void*” type for the data member ?

Thank you.
Best regards.

8-bit bytes are the standard size of byte to measure network
communications in. However, some machines have a different byte size:
some of the IBM mainframes, for example, use bytes somewhere around 36
bits in size (for a char they apparently cut these in half, but that’s
still 18 bits instead of 8). Thus, it makes sense to explicitly
specify through choice of datatype what the byte characteristics are.
I’ve never heard of SDL_net being ported to a machine that doesn’t use
8-bit bytes, but if it does happen, you can expect the
most-significant bits to be dropped from the value.

Incidentally, just in case you don’t have much exposure to network
coding, you are aware that different compilers and platforms create
structures of different sizes and internal alignments, right? The
Microsoft compilers, for example, apparently place each bitfield in
it’s own byte (or maybe it was an int for each?), whereas GCC places
them into as FEW bytes as it can on most platforms. Thus, even if it
SEEMS to work for you, please always remember to convert structures to
and from a “serialized” form when you’re sending them over the
network, or even just saving them to disk. Or, if nothing else,
remember to send a version id before sending the data, so that it can
be handled appropriately.> Date: Sun, 6 Oct 2013 16:27:05 +0200

From: YuGiOhJCJ Mailing-List
To: sdl at lists.libsdl.org
Subject: [SDL] the “UDPpacket” structure “data” member type

Date: Sun, 6 Oct 2013 18:08:04 +0200
From: YuGiOhJCJ Mailing-List
To: SDL Development List
Subject: Re: [SDL] the “UDPpacket” structure “data” member type
Message-ID: <20131006180804.3a6f93e83b2f985b4b196bd5 at laposte.net>
Content-Type: text/plain; charset=US-ASCII

In fact, I am using the C language, not the C++ language.
So, I have not access to reinterpret_cast.

C language casts are almost always reinterpret casts. C++ just added
the fancy name because:

  1. C++ has a few more casts, and
  2. C++ tried to make some things more explicit.

What you did below would qualify under the rules of the C++
static_cast (which does compile-time type checking), as well as
qualifying under the rules of the highly discouraged reinterpret_cast
(which just magically assumes that you’ve made certain that everything
will work, and thus feels free to say that the provided address just
points to a completely different type than it’s declared type:
dangerous, but useful).

I don’t think that it would qualify for dynamic_cast (which I recall
only working on classes with virtual functions), and const_cast would
similarly be the wrong mechanism.

Yes, I specify a size for the packet :

// Create the packet
UDPpacket *packet = NULL;
packet = SDLNet_AllocPacket(1024);

But this size of 1024 is not the same than the one in “packet->len”:

packet->len = 6;

Anyway, below is a source code that is working for a string.
Now, I would like to send a structure instead of this string.
For example, we can take this structure:
data.h :
typedef struct data
{
int integer;
char str[6];
} data_t;

Finally, I found the way how to cast correctly:

data_t data;
strcpy(data.str, “Hello\0”);
data.integer = 123;
packet->data = (Uint8*)&data;
packet->len = sizeof(data);

The data is correctly sent and received between the server and the client.

Problem solved.

From looking at this (
http://hg.libsdl.org/SDL_net/file/c98cd1a60729/SDLnetUDP.c ) file, a
few notes.

  1. Always set the status value on your packet to 0 before trying to
    send it. Afterwards, look at the value stored in status, and compare
    it with the packet length. If the status is smaller, then only part of
    the data was sent. You’ll need to do another send to get the rest out:
    a send which may require some house-keeping data to be sent as well,
    depending on the data format.
  2. Don’t place your own data buffer into the data pointer. There’s
    already a buffer there, of the size that you specified. To see what
    that size is, look at the maxlen member. If you need to change that
    size, use the SDLNet_ResizePacket() function.
  3. You do seem to have more-or-less parsed the correct use of the len
    member: it’s used to specify the amount of data to be sent, or that
    has been received. A value of 1 implies data[ 0 ], 2 implies data[ 0 ]
    & data[ 1 ], etc.

Unfortunately, for some reason, len is initially set to the size of
the packet structure, instead of being set to 0 or maxlen. I assume
that this is either a bug in the allocate function, or a peculiar
version-checking feature, intended to allow you to check whether the
packet size that the allocator expected is the packet size that YOU
expected.
While in some ways ingenious, this is really the sort of thing that I
would expect a version-checking function to do, especially since such
a function could also check the sizes and alignments of individual
members of the structure. At the very least it should be mentioned in
the documentation, and I didn’t notice such a thing.

2013/10/6 T. Joseph Carter > On Sun, Oct 06, 2013 at 06:31:36PM +0200, Jonas Kulla wrote:

2013/10/6 Jonas Kulla <@Jonas_Kulla>

Uhh, I have a feeling you’re just leaking memory here. Have you tried
doing this instead?

packet = SDL_NetAllocPacket(sizeof(**data_t));
memcpy(packet->data, &data;

I’m kinda sleepy, this is what it should have been:

packet = SDL_NetAllocPacket(sizeof(**data));
memcpy(packet->data, &data, sizeof(data));
packet->len = sizeof(data);

Mightn’t that fail if the machine the data is sent to happens to use a
different structure packing arrangement, uses a 64 bit integer, or any
number of things?

Of course, but his question was “how do I pump these bytes over the wire”,
I didn’t think proper serialization was in the scope of this.

Jonas

I figure anything worth explaining is worth explaining properly.
This is possibly unwise on my part because it’s led to a lot of long
messages lately that I know are just going to get lost in the list
archives. I really should spend the time working on the wiki or
actually writing tutorials or something. :stuck_out_tongue:

JosephOn Mon, Oct 07, 2013 at 09:44:03AM +0200, Jonas Kulla wrote:

Mightn’t that fail if the machine the data is sent to happens to use a
different structure packing arrangement, uses a 64 bit integer, or any
number of things?

Of course, but his question was “how do I pump these bytes over the wire”,
I didn’t think proper serialization was in the scope of this.