I am trying to send a structure over a socket in TCP. However when I receive the data at the structure I am getting an empty structure.
This is the structure being sent by the client:
typedef struct NwInfo
{
void *pvData;
NwTypes e_recv;
}NwInfo;
struct NwInfo test;
test.e_recv = 1;
test.pvData = (void *) &pst; //pst is object of another structure.
int ret =send(sockfd,&test,sizeof(test),0); //ret returns greater than 0
At the server side:
NwInfo *pRecvNwInfo;
pRecvNwInfo = malloc(sizeof(NwInfo));
int nbytes = recv(filedes,pRecvNwInfo,sizeof(NwInfo),0);
//nbytes is the same value as that of ret
struct student *pst;
pst = (struct student *)pRecvNwInfo->pvData;
The pst variable in the server side does not get any data. Could anyone point out the error I am making ?
There is no problem with your Socket Programming.
What you need to look at, is the logic.
Here the Server and Client are two different process, having its own address space.
Your Socket programming is perfectly fine.
For Example:
Client Side :
send(sockfd, &test, sizeof(test), 0)
printf ("Value of test->e_recv = [%d]\n", test.e_recv);
printf ("Value of test->ptr = [%u]\n", test.ptr);
$ ./client 172.16.7.110 56000
Value of test->e_recv = [1]
Value of test->ptr = [3214048236] // Address of some variable in Client address space.
Data Sent!
Server will recieve exactly the same data.
Server Side:
NwInfo *pRecvNwInfo = malloc(sizeof(NwInfo));
int nbytes = recv(filedes, pRecvNwInfo, sizeof(NwInfo), 0);
printf("Value of pRecvNwInfo->e_recv = [%d]\n", pRecvNwInfo->e_recv);
printf("Value of pRecvNwInfo->ptr = [%u]\n", pRecvNwInfo->ptr);
$./server 56000
Here is the message.
Value of pRecvNwInfo->e_recv = [1]
Value of pRecvNwInfo->ptr = [3214048236] // Address received correctly, but it is of client address space
So when you write this:
pst = (struct student *)pRecvNwInfo->pvData;
pst is pointing to the address, which is valid only in client address context.
So accessing it (in server's context) will give you Undefined Behavior, In my case SIGSEGV.
Important Note:
When you send, you are sending the data in the address of test and when you recv it, you are receiving the data in some new container (pRecvNwInfo) with a different address.
How to Rectify this:
Its best to send values and not the address.
Consider the following structure:
typedef struct inner
{
int a;
int b;
}inner_t;
typedef struct outer
{
void *ptr;
int c;
}outer_t;
You may change your Structure definition of outer:
Change the void * to actual data and not address, something like. inner_t var.
send(sockfd, &test, sizeof(test), 0);
Create a temporary structure type (for Sending & Receiving).
/* Temporary Buffer Declaration */
typedef struct temp{
inner_t value_in;
outer_t value_out;
} temp_t;
temp_t to_send;
inner_t buffer_in;
/* Save values instead of address */
memcpy(buffer_in, ptr, sizeof(inner_t));
to_send.value_in = buffer;
to_send.value_out = outer;
/* Send the final structure */
send(sockfd, &to_send, sizeof(temp_t), 0);
These may not be the best practices, I would love to know if there are any better ones.
You need to copy the value of pst in test.pvData member using memcpy. You are just assigning the memory address to test.pvData, value of which wont be available on server side. You can do something like this:
memcpy(test.pvData, &pst, sizeof pst);
Edit: You will also have to give some memory space to pvData instead of just being a pointer.
You cant just use sizeof(test) when sending the buffer since sizeof(test) will hold the size of the struct in the memory and since the data you wish to send is only pointed to by the struct it will NOT be included in that size.
instead,
hold the size of the data you wish to send, and create a stuct that will hold this value in a field and enough space to copy the data to it. then memcpy all the data to the struct and send it as a whole.
Anyhow I suggest you to fill the data directly in a struct you intend to send if you can this will save the memcpy.
Related
I am getting the below compilation error after upgrading to dpdk 18.08 version.
error: ‘struct rte_mbuf’ has no member named ‘pkt’
m->pkt.data = ((char*)m->pkt.data - (BTG_IP_VHL_HL(ip->version_ihl) << 2));
^
As per the documentation rte_mbuf struct no longer has packet message buffer struct rte_pktmbuf pkt which inturn holds void* data which contains start address of data in segment buffer.
struct rte_mbuf {
.
.
.
union {
struct rte_ctrlmbuf ctrl;
struct rte_pktmbuf pkt;
};
}
struct rte_pktmbuf {
/* valid for any segment */
struct rte_mbuf *next;
void* data; /**< Start address of data in segment buffer. */
Please let me know which other field of rte_mbuf struct can be used with dpdk 18.08 version which means start address of data in the packet message buffer so as to resolve this compilation error.Thanks in advance.
It's rte_pktmbuf_mtod(m, t) macro.
A macro that points to the start of the data in the mbuf.
The returned pointer is cast to type t. Before using this function, the user must ensure that the first segment is large enough to accommodate its data.
Source: DPDK API
Update:
To prepend a packet buffer with some data, there is a dedicated function for that: rte_pktmbuf_prepend() (and here is DPDK documentation)
It's hard to be 100% sure without the context of your old code, but it looks like this fragment must be rewritten to:
rte_pktmbuf_prepend(m,
BTG_IP_VHL_HL(ip->version_ihl) << 2);
I'm having problems with a client-server communication made with writev()/readv().
I have two struct, header and data defined like this:
typedef struct {
int op;
int key;
} message_hdr_t;
typedef struct {
int len;
char *data;
} message_data_t;
The server does (in short):
message_hdr_t h = {1, 11};
message_data_t d;
d.len = 3;
strcpy(d.data, "msg");
struct iovec tosend[2];
tosend[0].iov_base = &h;
tosend[0].iov_len = sizeof(message_hdr_t);
tosend[1].iov_base = &d;
tosend[1].iov_len = sizeof(message_data_t);
writev(socket, tosend, 2);
close(socket);
The client (in short):
struct iovec received[2];
readv(socket, received, 2);
message_hdr_t header;
header.op = ((message_hdr_t *) received[0].iov_base)->op;
header.key = ((message_hdr_t *) received[0].iov_base)->key;
printf("Received op: %i, key: %i\n",header.op,header.key;
close(socket);
But the client gets a segfault because received[0].iov_base is NULL. Why?
The socket is correctly opened and the client is correctly connected to the server. It's an AF_UNIX socket.
First, in your server code, you are writing a pointer. This makes no sense. You don't want to transmit pointers over the wire. To transmit a string, you have to do something like this:
char* message = ...;
message_hdr_t h = {1, 11};
uint32_t message_length = strlen(message);
struct iovec tosend[3];
tosend[0].iov_base = &h;
tosend[0].iov_len = sizeof(message_hdr_t);
tosend[1].iov_base = &message_length;
tosend[1].iov_len = sizeof(message_length);
tosend[2].iov_base = message;
tosend[2].iov_len = message_length;
(You may want to move the string length to the message header and save one element of the vector, and make the protocol more readable).
Second, readv won't allocate memory for you, or divine out how many bytes you want to read. It's your job to correctly initialize iov_base and iov_len in the IO vector passed to readv. In order to read a dynamically-allocated variable-size string, you probably want to read twice. First, read a part of the message that contains the length of the string, then allocate the string, and read the rest of the message.
I am implementing raw sockets in C. In the code below, I am parsing the IP header I received from sender.
a. I will send back the ack as well so storing IP address received in a buffer(ret_ip).
b. I don't have another computer so using lo (local loop back) as my interface.
//first two printf statements are printing the right address, 10.100.207.74
//daddr SENT = 32.112.247.9saddr SENT = 36.112.247.9
How can I get it correct?
I think this problem is due to memcpy whose first argument is pointing to unsigned char while second argument is pointing to _be32.
What I actually want to do in my program is : ret_ip's first 4 bytes should contain the destination address and next 4 the source address. Then I will create IP header and make dest addr=source addr and source-addr=dest-addr. and send ACK to sender.
char* ParseIPHeader(unsigned char *packet,int len)
{
struct ethhdr *ethernet_header;
struct iphdr *ip_header;
char *ret_ip;
ethernet_header=(struct ethhdr *)packet;
if(ntohs(ethernet_header->h_proto)==ETH_P_IP)
{
if(len>=(sizeof(struct ethhdr)+sizeof(struct iphdr)))
{
ip_header=(struct iphdr*)(packet+sizeof(struct ethhdr));
ret_ip=malloc(2*(sizeof(ip_header->daddr)));
printf("Dest IP address: %s\n",inet_ntoa(ip_header->daddr));
printf("Source IP address: %s\n",inet_ntoa(ip_header->saddr));
memcpy(ret_ip,&(ip_header->daddr),sizeof(ip_header->daddr));
memcpy(ret_ip+4,&(ip_header->saddr),4);
printf("daddr SENT = %s",inet_ntoa(ret_ip));
printf("saddr SENT = %s",inet_ntoa(ret_ip+4));
}
else
printf("IP packet does not have full header\n");
}
else
{
//not an IP packet
}
return ret_ip;
}
Thanks :)
first problem is your memory allocation
ret_ip=malloc(2*(ip_header->daddr));
it should be
ret_ip=malloc(2*(sizeof(ip_header->daddr)));
but why you are not using the ip_hdr struct again ? for example
struct iphdr *ret_ip = malloc(sizeof(iphdr));
ret_ip->daddr = ip_header->saddr;
ret_ip->saddr = ip_header->daddr;
i suggest this solution is much easier ;)
I just want to send an array adc_array=[w, x, y, z] from client to server. Below is the client side code whereas my server is in python which accepts json only. I get no error when i compile the code however get 2 warnings :
1- warning: pointer targets in passing argument 2 of 'UDPWrite' differ in signedness.
2- warning: no newline at end of file.
But at the server side, i am not able to receive the whole array, instead i just get the first character of the array i.e. [ .
I am new to C programming. I would really appreciate any help.
// Main function
void FlyportTask()
{
// Flyport connects to default network
WFConnect(WF_DEFAULT);
while(WFGetStat() != CONNECTED);
vTaskDelay(25);
UARTWrite(1,"Flyport Wi-fi connected...hello world!\r\n");
BOOL UdpSocketOpenRequest=TRUE;
BYTE UdpSocket=0;
// openinging UDP socket
if (UdpSocketOpenRequest) //open socket
{
UdpSocketOpenRequest=FALSE;
if (UdpSocket!=0) //if this is not equals to zero
{
UDPClientClose(UdpSocket);
}
UARTWrite(1,"OpenSocket\r\n");
UdpSocket= UDPClientOpen("10.0.0.106", "8000"); //Client socket opening
}
while(1)
{
//defining pointer
int *array_pointer;
int adc_array[4];
int j;
char buf[10]; //buffer to print
// I have made a separate function to get adc values which returns the pointer to the array.
array_pointer = get_adcval();
UARTWrite (1, "ADC Array\r\n");
for (j = 0; j < 4; j++)
{
adc_array[j] = *(array_pointer + j);
sprintf (buf, "%d", adc_array[j]);
UARTWrite (1, buf);
UARTWrite (1, "\n");
}
//if UDP socket is open, send the data
if ((UdpSocket!=0))
{
// defining pointer of serial_out
char *s_out;
int size;
// creating a JSON array from adc_array with 4 elements
cJSON * int_array = cJSON_CreateIntArray(adc_array,4);
// Serializing the array
s_out = cJSON_Print(int_array);
//Writing to the serial output/monitor
UARTWrite(1, "\r\narray to be sent\r\n");
UARTWrite(1, s_out);
UARTWrite(1,"\r\n");
// Assume adc_array=[1021, 1022, 1023, 1024]
// I get output [1021, 1022, 1023, 1024]
//compose message
size = strlen(s_out);
UDPWrite (UdpSocket, s_out, size);
// at the server side, i just receive only first character i.e. [
/*to free the memory */
free(s_out);
}
//
// remember to add delay vTaskDelay(50) 50ms
//remember to close the socket
}
}
You didn't allocated memory for s_out. even if it is printing correct result on UART but still it can be overwritten by any of the UARTWrite functions or strlen() function in the next lines. If it is overwritten then the "size" variable will get the number of bytes starting from the first byte to first null character in the memory (this is how strlen() functions). hence the "size" value can be totally random. it can be 0 or 1 or 1000. if the size is not correct then you will receive only "size" number of bytes. In your case it is possible that size is one. try printing size before UDPWrite. fix this problem by adding a malloc call before serializing the array.
If it doesn't work either then check your receiver side. is your receiver working fine if you send some dummy data from a tested python client (or any other tested or reliable client)? if no then there is some problem with your receiver.
Print out what strlen(s_out) returns, also print out the return value of UDPWrite ( I assume that like any write function this will be returning the size of the data which is written to the socket).
By reading the function names I presume you are using UDP transmission which is unreliable.
I am trying to send data between a client/Server, the data looks like
typedef Struct Message
{ int id;
int message_length;
char* message_str;
}message;
I am trying to Write and Read this message between a client and server constantly updating the elements in this struct. I have heard Writev may do the trick. i want to send a
message to the server and then the server pulls out the elements and uses those elements as conditionals to execute the proper method?
Assuming you want to do the serialization yourself and not use Google Protocol Buffers or some library to handle it for you, I'd suggest writing a pair of functions like this:
// Serializes (msg) into a flat array of bytes, and returns the number of bytes written
// Note that (outBuf) must be big enough to hold any Message you might have, or there will
// be a buffer overrun! Modifying this function to check for that problem and
// error out instead is left as an exercise for the reader.
int SerializeMessage(const struct Message & msg, char * outBuf)
{
char * outPtr = outBuf;
int32_t sendID = htonl(msg.id); // htonl will make sure it gets sent in big-endian form
memcpy(outPtr, &sendID, sizeof(sendID));
outPtr += sizeof(sendID);
int32_t sendLen = htonl(msg.message_length);
memcpy(outPtr, &sendLen, sizeof(sendLen));
outPtr += sizeof(sendLen);
memcpy(outPtr, msg.message_str, msg.message_length); // I'm assuming message_length=strlen(message_str)+1 here
outPtr += msg.message_length;
return (outPtr-outBuf);
}
// Deserializes a flat array of bytes back into a Message object. Returns 0 on success, or -1 on failure.
int DeserializeMessage(const char * inBuf, int numBytes, struct Message & msg)
{
const char * inPtr = inBuf;
if (numBytes < sizeof(int32_t)) return -1; // buffer was too short!
int32_t recvID = ntohl(*((int32_t *)inPtr));
inPtr += sizeof(int32_t);
numBytes -= sizeof(int32_t);
msg.id = recvID;
if (numBytes < sizeof(int32_t)) return -1; // buffer was too short!
int32_t recvLen = ntohl(*((int32_t *)inPtr));
inPtr += sizeof(int32_t);
numBytes -= sizeof(int32_t);
msg.message_length = recvLen; if (msg.message_length > 1024) return -1; /* Sanity check, just in case something got munged we don't want to allocate a giant array */
msg.message_str = new char[msg.message_length];
memcpy(msg.message_str, inPtr, numBytes);
return 0;
}
With these functions, you are now able to convert a Message into a simple char-array and back at will. So now all you have to do is send the char-array over the TCP connection, receive it at the far end, and then Deserialize the array back into a Message struct there.
One wrinkle with this is that your char arrays will be variable-length (due to the presence of a string which can be different lengths), so your receiver will need some easy way to know how many bytes to receive before calling DeserializeMessage() on the array.
An easy way to handle that is to always send a 4-byte integer first, before sending the char-array. The 4-byte integer should always be the size of the upcoming array, in bytes. (Be sure to convert the integer to big-endian first, via htonl(), before sending it, and convert it back to native-endian on the receiver via htonl() before using it).
Okay, I'll take a stab at this. I'm going to assume that you have a "message" object on the sending side and what you want to do is somehow send it across to another machine and reconstruct the data there so you can do some computation on it. The part that you may not be clear on is how to encode the data for communications and then decode it on the receiving side to recover the information. The simplistic approach of just writing the bytes contained in a "message" object (i.e. write(fd, msg, sizeof(*msg), where "msg" is a pointer to an object of type "message") won't work because you will end up sending the value of a virtual address in the memory of one machine to different machine and there's not much you can do with that on the receiving end. So the problem is to design a way to pass an two integers and a character string bundled up in a way that you can fish them back out on the other end. There are, of course, many ways to do this. Does this describe what you are trying to do?
You can send structs over socket, but you have to serialize them before sending the struct using boost serialization.
Here is a sample code :
#include<iostream>
#include<unistd.h>
#include<cstring>
#include <sstream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
using namespace std;
typedef struct {
public:
int id;
int message_length;
string message_str;
private:
friend class boost::serialization::access;
template <typename Archive>
void serialize(Archive &ar, const unsigned int vern)
{
ar & id;
ar & message_length;
ar & message_str;
}
} Message;
int main()
{
Message newMsg;
newMsg.id = 7;
newMsg.message_length = 14;
newMsg.message_str="Hi ya Whats up";
std::stringstream strData;
boost::archive::text_oarchive oa(strData);
oa << newMsg;
char *serObj = (char*) strData.str().c_str();
cout << "Serialized Data ::: " << serObj << "Len ::: " << strlen(serObj) << "\n";
/* Send serObj thru Sockets */
/* recv serObj from socket & deserialize it */
std::stringstream rcvdObj(serObj);
Message deserObj;
boost::archive::text_iarchive ia(rcvdObj);
ia >> deserObj;
cout<<"id ::: "<<deserObj.id<<"\n";
cout<<"len ::: "<<deserObj.message_length<<"\n";
cout<<"str ::: "<<deserObj.message_str<<"\n";
}
you can compile the program by
g++ -o serial boost.cpp /usr/local/lib/libboost_serialization.a
you must have libboost_serialization.a statically compiled in your machine.
Keeping the sockets 'blocking' will be good and you have to devise for reading these structs from recv buffer.