0

I am facing a bit of issue in writing a network software. When I try to send or receive a struct that contains a data type of 8 bytes the next sent or received struct is somehow affected. I have a few things in mind but first I wanted to confirm one thing before I get into debugging. I am using 32-bit Ubuntu 11.04 (silly me) on a 64-bit x-86 system. Does this has anything to do with the byte alignment problems?

I am developing a controller to communicate with the Open Flow switch. The openflow protocol defines a set of specs based on which switches are built. The problem is when I try to communicate with the switch everything goes fine until I send or receive a struct that contains a 64 bit date type (uint64_t). The specific structs that are used for sending and receiving features are

estruct ofp_header {
uint8_t version;    /* OFP_VERSION. */
uint8_t type;       /* One of the OFPT_ constants. */
uint16_t length;    /* Length including this ofp_header. */
uint32_t xid;       /* Transaction id associated with this packet.
                       Replies use the same id as was in the request
                       to facilitate pairing. */};   
 assert(sizeof(struct ofp_header) == 8);




/* Switch features. */
struct ofp_switch_features {
struct ofp_header header;
uint64_t datapath_id; /* Datapath unique ID. The lower 48-bits are for a MAC address, while the upper 16-bits are implementer-defined. */
uint32_t n_buffers; /* Max packets buffered at once. */
uint8_t n_tables; /* Number of tables supported by datapath. */
uint8_t pad[3]; /* Align to 64-bits. */

/* Features. */ /* Bitmap of support "ofp_capabilities". */
uint32_t capabilities; /* Bitmap of supported "ofp_action_type"s. */
uint32_t actions; 

/* Port info.*/
struct ofp_phy_port ports[0];  /* Port definitions. The number of ports is inferred from the length field in the header. */
};
assert(sizeof(struct ofp_switch_features) == 32);

The problem is when I communicate using any other structs that have data types less than 64-bit everything goes fine. When I receive features reply it shows the right values but after that if I receive any other struct it shows garbage values. Even if I receive features reply again I get garbage values. In short if at any point of code I receive features request or any other struct defined in the specs that has a data type of 64-bit the next structs receive garbage values. The code used for sending and receiving features request is as follows

////// features request and reply  ////////////

ofp_header features_req;

features_req.version=OFP_VERSION;
features_req.type=OFPT_FEATURES_REQUEST;
features_req.length= htons(sizeof features_req);
features_req.xid = htonl(rcv_hello.xid);


if (send(connected, &features_req, sizeof(features_req), 0)==-1) {
printf("Error in sending message\n");
exit(-1);
}
printf("features req sent!\n");



ofp_switch_features features_rep={0};

if (recv(connected, &features_rep, sizeof(features_rep), 0)==-1) {
printf("Error in receiving message\n");
exit(-1);
}

printf("message type : %d\n",features_rep.header.type);
printf("version : %d\n",features_rep.header.version);
printf("message length: %d\n",ntohs(features_rep.header.length));
printf("xid : %d\n",ntohl(features_rep.header.xid));
printf("buffers: %d\n",ntohl(features_rep.n_buffers));
printf("tables: %d\n",features_rep.n_tables);
Cœur
  • 37,241
  • 25
  • 195
  • 267
Abdullah
  • 521
  • 2
  • 8
  • 20
  • How are you sending the struct? – Oliver Charlesworth Nov 10 '11 at 17:42
  • 1
    "somehow affected" doesn't help us much. affected how? – Marc B Nov 10 '11 at 17:42
  • 4
    Don't "send a struct". Send individual, fundamental types, or strings of bytes. – Kerrek SB Nov 10 '11 at 18:00
  • @abshah: Is the structure packed? Because normally it would fail that assert – Mooing Duck Nov 10 '11 at 18:16
  • I ve added the complete description please have a look – Abdullah Nov 10 '11 at 18:49
  • @MooingDuck Yes the structs are 64 bit alligned – Abdullah Nov 10 '11 at 18:50
  • @abshah - As I mentioned below - convert the struct into an array of characters before sending it! Then unpack it on the receiving end into a new struct – Ed Heal Nov 10 '11 at 18:58
  • Nothing in your description sounds like the problem has anything at all to do with the 64 bit data type. Why do you think that it is affecting things? – Mooing Duck Nov 10 '11 at 19:06
  • @MooingDuck- As I mentioned if I receive or send any struct that has a 64-bit data type in it, causes the problems. If I use any other structs (there are a lot of them in openflow specs) that dont have a type 64-bit doesnt cause any problem at all. That is really bothering me :/ – Abdullah Nov 10 '11 at 19:12
  • Could there be anything else that I am missing ? I would really appreciate some help here. – Abdullah Nov 10 '11 at 19:15
  • @abshah: you are sending/receiving 64-bit types when the switch is not receiving/sending 64-bit types. Reread your specification document. – Mooing Duck Nov 10 '11 at 19:32
  • @MooingDuck -- I gave the struct in the description ie ofp_switch_features. That is the struct defined in the specs of the switch and that is what it sends to the controller it is connected to. So I am receiving a 64 bit type as sent from the switch but it just somehow disturbs everything after that. – Abdullah Nov 10 '11 at 19:51
  • @Abdullah: The only explanation is you are not sending or receiving the correct number of bits somehow. If it only happens with the 64 bit types... Are you sure there's not a slightly different spec for your specific model/OS/settings/etc? – Mooing Duck Nov 10 '11 at 21:17
  • @MooingDuck-- that is exactly what I am confused about and hence asked that 32 bit os running on 64 bit architecture wouldn't cause problems would it ? – Abdullah Nov 10 '11 at 21:32

5 Answers5

6
  1. Convert your struct into an array of characters before sending them - this is call serialisation
  2. Use the family of functions htons etc to ensure that integers are sent in network order. Saves hassle on the endians of the various machines
  3. One the recieving end read the bytes and reconstruct the struct.

This will ensure that you will not have any hassle at all.

Ed Heal
  • 59,252
  • 17
  • 87
  • 127
  • Construct an array of characters of the correct size and populate it. I have given you the pointers as to the functions to use. `memcpy` would be useful to do the population. e.g. `short x = 3; x = htons(x); memcpy(buffer+3, (char *)&x, sizeof(short)));` – Ed Heal Nov 10 '11 at 17:58
1

Here is what is want

features_req.version=OFP_VERSION; 
features_req.type=OFPT_FEATURES_REQUEST; 
features_req.length= htons(sizeof features_req); 
features_req.xid = htonl(rcv_hello.xid); 

char data[8];
data[0] = features_req.version;
data[1] = features_req.type;
memcpy(data + 2, &features_req.length, 2);
memcpy(data + 4, &features_req.xid, 4);

if (send(connected, data, 8) ....

On the receving end

char data[8];

if (recv(conncted, data, 8) ...
features_req.version = data[0];
features_req.type = data[1];
memcpy(&features_req.length, data + 2, 2);
memcpy(&features_req.xid, data + 4, 4);

features_req.length = ntohs(features_req.length);
features_req.xid= ntohl(features_req.xid);
Ed Heal
  • 59,252
  • 17
  • 87
  • 127
1

I got help from Daniweb.com and all credit goes to a guy with a nick NEZACHEM. His answer was, and I quote :

The problem has nothing to do with 64 bit types. Values you read are not garbage, but a very valuable port definitions:

 struct ofp_phy_port ports[0];  /* Port definitions. The number of ports is inferred from the length field in the header. */

Which means, once you've

recv(connected, &features_rep, sizeof(features_rep), 0)

you need to inspect features_rep.header.length, figure out how many struct ofp_phy_port follow, allocate memory for them and read those data.

I did that and thanks to him my problems were solved and all went well :) thanx for everyone that replied. cheers :)

Prof. Falken
  • 24,226
  • 19
  • 100
  • 173
Abdullah
  • 521
  • 2
  • 8
  • 20
0

You could even consider using serialization techniques: perhaps JSON, XDR, YAML could be relevant. or libraries like s11n, jansson, etc.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
0

1 In case you stick to sending the structures you should make sure they are byte aligned.

To do so use the pragma pack like this:

#pragma pack(1)
struct mystruct{
  uint8_t  myint8;   
  uint16_t myint16;   
};
#pragma pack()

Doing so you makes sure this structure does use 3 bytes only.

2 For converting 64bit values from host order to network order this post reads interessing: Is there any "standard" htonl-like function for 64 bits integers in C++? (no, it only starts with c++ and ends with C also)

Community
  • 1
  • 1
alk
  • 69,737
  • 10
  • 105
  • 255