Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can we typecast buffer into C++ structure on client when server is sending data as c structure?

Tags:

c++

c

linux

sockets

I have server, client processes written in C named as NetworkServer.c and NetworkClient.c and these 2 are communicating using linux sockets. When client sends a request as below to get ethernet statistics,

// rxbuf - character array of 128K
// ETHERNET_DIAGNOSTIC_INFO - structure typedefed
recv(sockfd, rxbuf, sizeof(ETHERNET_DIAGNOSTIC_INFO), 0)

server fills the data in to rxbuf (as ETHERNET_DIAGNOSTIC_INFO because server also uses the same copy of header file where this structure is defined) and sends the data. Once client receives, it will typecast as below to get the data.

ETHERNET_DIAGNOSTIC_INFO *info = (ETHERNET_DIAGNOSTIC_INFO *) rxbuf;

the structure is defined in NetworkDiag.h as below.

#ifdef __cplusplus
extern "C" {
#endif

typedef struct ETHERNET_DIAGNOSTIC_INFO
{
    uint32_t             cmdId; 
    unsigned long        RxCount[MAX_SAMPLES];
    unsigned long        TxCount[MAX_SAMPLES];
    time_t               TimeStamp[MAX_SAMPLES] ;
    char                 LanIpAddress[20];
    char                 LanMacAddress[20];
    char                 WanIpAddress[20];
    char                 LanDefaultGateway[20];
    char                 LanSubnetMask[20];
    char                 LanLease[5000];
}ETHERNET_DIAGNOSTIC_INFO;

This is working fine.

Now there is a requirement that I need to create a c++ file which should work as client (I removed client C file and server should remain as c file). I defined header file for the structure definition as below.

struct ETHERNET_DIAGNOSTIC_INFO
{
    uint32_t             cmdId; 
    unsigned long        RxCount[MAX_SAMPLES];
    unsigned long        TxCount[MAX_SAMPLES];
    time_t               TimeStamp[MAX_SAMPLES] ;
    char                 LanIpAddress[20];
    char                 LanMacAddress[20];
    char                 WanIpAddress[20];
    char                 LanDefaultGateway[20];
    char                 LanSubnetMask[20];
    char                 LanLease[5000];
};

basically I removed the C++ guard and typedef and using the below code in client.cpp file to get the result from server.

if(recv(sockfd, rxbuf, sizeof(ETHERNET_DIAGNOSTIC_INFO), 0) > 0)
{
    ETHERNET_DIAGNOSTIC_INFO *info = reinterpret_cast<ETHERNET_DIAGNOSTIC_INFO *> (rxbuf);
}

I am not getting the correct results. The values in the structure are misplaced (some values are correct but lot of values are misplaced). I tried 'C' type casting also but no use.

I doubt that we can not typecast buffer into C++ structure on client when server is sending data as c structure. Is it correct? Can any one please let me know how to solve this issue?

like image 762
kadina Avatar asked Sep 16 '15 20:09

kadina


People also ask

What are the advantages of typecasting in programming?

In such cases, typecasting can help to get correct output and reduce the time of compilation. Take a step-up from those "Hello World" programs. Learn to implement data structures like Heap, Stacks, Linked List and many more!

What is type casting in C++?

Type casting is a way to convert a variable from one data type to another data type. For example, if you want to store a 'long' value into a simple integer then you can type cast 'long' to 'int'. You can convert the values from one type to another explicitly using the cast operator as follows −. (type_name) expression.

What is narrowing conversion in typecasting?

In typecasting, the destination data type may be smaller than the source data type when converting the data type to another data type, that’s why it is also called narrowing conversion. There are some cases where if the datatype remains unchanged, it can give incorrect output.

When to use the cast operator in C?

It is considered good programming practice to use the cast operator whenever type conversions are necessary. Integer promotion is the process by which values of integer type "smaller" than int or unsigned int are converted either to int or unsigned int. Consider an example of adding a character with an integer −


1 Answers

There are multiple problems with this approach:

  1. Endianness might be different between server and client machine

    You then need to deserealize numbers and time_t's.

  2. Structure packing might be different between code compiled on server (c++) and on client (C)

    You then need to use a protocol to send data, like binary ASN, protobuf or many others.

  3. if(recv(sockfd, rxbuf, sizeof(ETHERNET_DIAGNOSTIC_INFO), 0) > 0) there is no guarantee recv will read exactly sizeof(ETHERNET_DIAGNOSTIC_INFO) bytes.

    You need to wrap this into while loop (code is sample and might be non-compilable):

.

int left = sizeof(ETHERNET_DIAGNOSTIC_INFO);
char *ptr = rxbuf;
int rd;

while(left>0)
{
    rd=recv(sockfd, ptr, left, 0);
    if(rd==0)
    {
        if(left>0) return SOCKET_CLOSED_PREMATURELY;
        else return SOCKET_DONE;
    } else if(rd==-1 && errno==EAGAIN) {
        //do again
        continue; 
    } else if(rd==-1 && errno!=EAGAIN) {
       return SOCKET_ERROR;
    }
    left = left - rd;
    ptr=ptr+rd;
}

The proper way to send binary data is to use protobuf or apache thrift, or ASN or invent something yourself.

like image 136
fukanchik Avatar answered Oct 19 '22 13:10

fukanchik