buffer size

E

erbm

Hello people. I'm learning C and I'm doing a simple client-server
aplication, and so I'm using 2 fuctions to serialize and deserialize a
struct to/from an array of bytes and send it to the server.

struct product_t {
int size_n; // name size
char* name;
int price;
};

and the serialization format is:

NAMESIZE NAME PRICE
[4byte] [NAMESIZE bytes] [4 byte]

The functions are:

int product_to_buffer(struct product_t *prod, char **buffer)
{

char *buf = *buffer;
uint32_t size = sizeof(uint32_t) + strlen(prod->name) + sizeof
(uint32_t);

buf = malloc (size);
*buffer = buf;
char* pos = buf;

uint32_t name_size = htonl(prod->size_n);
unsigned char* bytes = (unsigned char*) &name_size;
memcpy(pos, bytes, sizeof (size));
pos+= sizeof (size);

char auxName[prod->size_n];
strcpy(auxName, prod->name);
memcpy(pos, auxName, prod->size_n);
pos+= prod->size_n;

uint32_t price = htonl(prod->price);
bytes = (unsigned char*) &price;
memcpy(pos, bytes, sizeof (uint32_t));
pos+= sizeof (size);

return size; //number of bytes allocated
}

struct product_t *buffer_to_product(int buflen, char *buffer)
{
if (buflen < 2 * sizeof(uint32_t) || buffer == NULL)
return NULL;

struct product_t* prod = (struct product_t*) malloc(sizeof (struct
product_t));

char* pos = buffer;

uint32_t price, name_size;

memcpy(&name_size, pos, sizeof (uint32_t));
prod->size_n = ntohl(name_size);
prod->name = malloc(ntohl(name_size));
pos += sizeof (uint32_t);

char name[prod->size_n];
memcpy(name, pos, prod->size_n);
strcpy(prod->name, name);
prod->name[prod->size_n] = '\0' ;
pos += prod->size_n;

memcpy(&price, pos, sizeof (uint32_t));
prod->price = ntohl(price);

return prod;
}

It looks like they work correctly. For example, If I call:

char* buffer;
int size = product_to_buffer(&prod, &buffer);

and :
struct product_t* prod2 = buffer_to_product(size, buffer);

i am able to restore the original product successfuly.
The problem is finding the size of se buffer after the serialization.

int buf_size = strlen(buffer);

return 0, and so i cant copy the buffer and find the number of bytes.
Yes, the variable size contains the length, but in some situations i
dont have this information but I still need to find the length of the
buffer.
Any ideia of what is happening? Returnig 0 on strlen is the same as
telling me the buffer is empty, isn't it? But, it works when I use the
buffer to deserialize.
Goog night
 
B

Barry Schwarz

Hello people. I'm learning C and I'm doing a simple client-server
aplication, and so I'm using 2 fuctions to serialize and deserialize a
struct to/from an array of bytes and send it to the server.

struct product_t {
int size_n; // name size
char* name;
int price;
};

and the serialization format is:

NAMESIZE NAME PRICE
[4byte] [NAMESIZE bytes] [4 byte]

The functions are:

int product_to_buffer(struct product_t *prod, char **buffer)
{

char *buf = *buffer;
uint32_t size = sizeof(uint32_t) + strlen(prod->name) + sizeof
(uint32_t);

buf = malloc (size);
*buffer = buf;
char* pos = buf;

uint32_t name_size = htonl(prod->size_n);

Not knowing anything about htonl, is it safe to assume it always
returns a 32 bit value?
unsigned char* bytes = (unsigned char*) &name_size;
memcpy(pos, bytes, sizeof (size));

Since memcpy takes two void*, there is not benefit to using bytes.
memcpy(pos, &name_size, sizeof name_size);
pos+= sizeof (size);

char auxName[prod->size_n];
strcpy(auxName, prod->name);
memcpy(pos, auxName, prod->size_n);

auxName serves no purpose here either.
memcpy(pos, prod->name, prod->size_n);
pos+= prod->size_n;

uint32_t price = htonl(prod->price);
bytes = (unsigned char*) &price;
memcpy(pos, bytes, sizeof (uint32_t));

Ditto for bytes.
pos+= sizeof (size);

return size; //number of bytes allocated
}

struct product_t *buffer_to_product(int buflen, char *buffer)
{
if (buflen < 2 * sizeof(uint32_t) || buffer == NULL)
return NULL;

struct product_t* prod = (struct product_t*) malloc(sizeof (struct
product_t));

Don't cast the return from malloc.
char* pos = buffer;

uint32_t price, name_size;

memcpy(&name_size, pos, sizeof (uint32_t));
prod->size_n = ntohl(name_size);
prod->name = malloc(ntohl(name_size));

It would be simpler to use
prod->name = malloc(prod->size_n);
pos += sizeof (uint32_t);

char name[prod->size_n];
memcpy(name, pos, prod->size_n);
strcpy(prod->name, name);

name serves no purpose here either.
memcpy(prod->name, pos, prod->size_n);
prod->name[prod->size_n] = '\0' ;

If the '\0' was not already present, then your strcpy above would
invoke undefined behavior.
pos += prod->size_n;

memcpy(&price, pos, sizeof (uint32_t));
prod->price = ntohl(price);

return prod;
}

It looks like they work correctly. For example, If I call:

char* buffer;
int size = product_to_buffer(&prod, &buffer);

and :
struct product_t* prod2 = buffer_to_product(size, buffer);

i am able to restore the original product successfuly.
The problem is finding the size of se buffer after the serialization.

int buf_size = strlen(buffer);

return 0, and so i cant copy the buffer and find the number of bytes.

product_to_buffer returns the size of the buffer. Code of the form
buf_size = product_to_buffer(&prod, &buffer);
should do what you want.
Yes, the variable size contains the length, but in some situations i
dont have this information but I still need to find the length of the
buffer.

What information don't you have? What is in the first four bytes of
buffer? Does not the expression
2*sizeof(uint32_t) + strlen(pos+sizeof(uint32_t)) + 1
produce the value you want? And if you subtract 2*sizeof(uint32_t)
from this value, does it not give you the value that should be in the
first four bytes after conversion by htonl?
Any ideia of what is happening? Returnig 0 on strlen is the same as
telling me the buffer is empty, isn't it? But, it works when I use the

buffer does not point to a string. It points to the first of four
bytes that have been massaged by htonl. This is usually a big-endian
value so unless your string is over 16MB, the first byte of the value
will be 0x00. If you try to treat this is as a string, it is a zero
length string that consists of nothing but the terminating nul
character.

On the other hand, buffer + sizeof(uint32_t) does point to the string.
Hence the formula above.
 
Q

qarnos

Any ideia of what is happening? Returnig 0 on strlen is the same as
telling me the buffer is empty, isn't it? But, it works when I use the
buffer to deserialize.
Goog night

The strlen() function is used to determine the length of a null (0)
terminated string. Using it on buffers of arbitrary data is
meaningless.

In this case, the first piece of data you are serialising - size_n -
(almost) certainly contains zeros in the upper bytes. Since htonl()
orders the bytes in big-endian format (if they aren't already), the
first byte written to the buffer is zero.

For instance, a 32-bit big-endian integer loaded with the value 513
would have the following 4 byte-values on most machines:

0, 0, 2, 1

Notice the first byte! If you try to call strlen() on this data, it
will return zero.

Why not write the size of the buffer as the first item in the buffer
instead?

HTH.
 
K

Kenny McCormack

Barry Schwarz said:
Not knowing anything about htonl, is it safe to assume it always
returns a 32 bit value?

If you don't know anything about something (in this case, the
"something" is the "htonl()" function, then it isn't safe (for you) to
assume anything.

Instead, you should be reading up and informing yourself, so as to
reduce your ignorance.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,061
Latest member
KetonaraKeto

Latest Threads

Top