Send a XDR struct over a socket with C in Linux - c

I'm writing a server that send an XDR struct over a socket.
Using Wireshark I see that my client correctly send an XDR message to the server BUT I don't see any data go from the server to the client. But the code seems to be correct as it is the same used for the client. I have see that the problem is xdr_Response. Is there any mistake on it? Thanks to all
XDR xdrs_w;
Response y;
stream_socket_w = fdopen(s, "w");
xdrstdio_create(&xdrs_w, stream_socket_w, XDR_ENCODE);
y.error = 0;
y.result = 5.7;
xdr_Response(&xdrs_w, &y);
fflush(stream_socket_w);
with:
struct Response {
bool_t error;
float result;
};
typedef struct Response Response;

I'm not very expert of XDR, but I found a way that worked to receive data from XDR with a socket connection (on TCP). First you have to do recv to receive the data from your client, then call xdrmem_create(), that need the XDR structure that you'll use to the reading, a buffer (a string), the return value of recv(), and you have to use XDR_DECODE because you're writing from XDR that's codified.
You have to write something like this:
l = recv(socket, buffer, BUFFERDIM, 0);
xdrmem_create(&xdrs_w, buff, l, XDR_DECODE );
if(!xdr_Response(&xdrs_w, &y) {
fprintf(stdout, "Error XDR\n");
}
fprintf(stdout, "Received: %f", y.result);
and y should be filled in. Note that buffer is different from buff. I prefer to do this instead of use fd_open, you've only to create the xdr and call xdr_Response.

Related

C binary message over amqp

Currently I have a daemon listening for TCP/UDP packets on port X using the recvfrom system call:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
and then the data is send over a message queue with the msgsnd system call:
int msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflg);
I would like to replace the msgsnd system call with RabbitMQ and send the messages using amqp protocol. The problem I am facing is the format of the data received and send over the RabbitMQ. When I receive data on port then I try to send it like this:
ssize_t recvfrom(
sockfd, msgbufInst.msgContent, len, flags, src_addr, addrlen
);
send_over_rabbitmq(msgbufInst.msgContent);
where send_over_rabbitmq is pretty much
send_over_rabbitmq(char *rawData){
amqp_bytes_t payload;
payload.len = sizeof(rawData);
payload.bytes = rawData;
int result = amqp_basic_publish((*channel)->conn, 1,
amqp_cstring_bytes("myExchange"),
amqp_cstring_bytes(""), 0, 0, NULL, payload);
}
The payload is send and received successfully but some data is lose. When I consume the message from the queue the payload is not the same as when I used the system call to send/consume messages. I am sure that it has to do with the data types that I am using but can't figure it out yet.
As I noted in a comment:
In the send_over_rabbitmq() function, the value of sizeof(rawData) is probably 8, and maybe only 4 — it's the size of the pointer variable, and not the length of the data that it points at. That probably isn't what you want.
You'll need to send more information to the send_over_rabbitmq() function — most noticeably, the length of the data received from recvfrom(). That means capturing the information — you should be checking the return value from recvfrom() anyway before trying to relay information via RabbitMQ.

C Sockets: recv() blocks when all data is downloaded [duplicate]

This question already has an answer here:
Differ between header and content of http server response (sockets)
(1 answer)
Closed 4 years ago.
I'm writing a wrapper for Berkley sockets on Windows and Linux. The test program got problem here:
char buf[BUFSIZE];
int res = 0;
while((res = NetRecv(sock, buf, BUFSIZE, 0)) > 0) // 'NetRecv' is pointing to 'recv'
{
buf[res-1] = '\0';
printf("%s", buf);
}
The response is to a HTTP-Get request of a web-page content. The socket is streaming.
The 'NetRecv' is initialized correctly - that is, no type mismatch of the functions' pointers there is, I've checked it.
So, Windows version works flawlessly, the Linux one is stuck after reading all page. Namely, the previous to the last 'NetRecv' call accepts last chunk of the response, outputs it, and the next (last) call just blocks. Closing the terminal causes 'SIGHUP' signal.
Looks like the Linux version just doesn't realize, that it received the last chunk of data and waits for more.
Is it as it should be? Don't understand then, for what reason there is blocking call possibility.
Now, I surely could make non-blocking call and use 'select', but do I really have to?
Thanks in advance)
EDIT: Minimal working example (all checks are omitted and net functions are the standard ones, which also were tested):
int sock = socket(AF_INET, SOCK_STREAM, 0);
// Here getting good IP address of google.com - no problem here
char serv_ip[IPADDR_BUFSIZE];
GetHostAddrByName(AF_INET, "www.google.com", serv_ip, IPADDR_BUFSIZE);
// ip ver site out buf out buf size
// The routine above is made with 'getaddrinfo', to be precise
printf("Current IP of '%s' is '%s'.\n", SERV_URL, serv_ip);
// Copying IP string to address struct
struct sockaddr_in addr;
NetIpFromStr(AF_INET, serv_ip, &addr.sin_addr);
addr.sin_family = AF_INET;
addr.sin_port = NetHtons(80);
connect(sock, (const struct sockaddr*)&addr, sizeof(addr));
const char* msg = "GET / HTTP/1.1\r\n\r\n";
send(sock, msg, strlen(msg), 0);
char buf[BUFSIZE];
int res = 0;
while((res = recv(sock, buf, BUFSIZE-1, 0)) > 0)
{
buf[res] = '\0';
printf("%s", buf);
}
EDIT 2: Important notice: the Windows version also blocks the call, when all the data is read. Closing the terminal just doesn't crash the program, like it happens in Linux. Therefore, the whole question is such: How to realize that all data is read?
The problem is that you are blindly reading from the socket in a loop until an error occurs. Once you have received the entire response, you go back to the socket and keep reading, which then blocks because there is nothing left to read. The only error that can occur at this point is when the connection is closed (or lost), which the server is likely not doing since you are sending an HTTP 1.1 request, where keep-alive is the default behavior for 1.1 (see RFC 2616 Section 8.1 Persistent Connections)
The correct solution is to parse the HTTP response and stop reading from the socket when you reach the end of the response, NOT simply relying on the server to close the socket. Read RFC 2616 Section 4.4 Message Length for how to detect when you have reached the end of the response. DO NOT read more than the response indicates! Once you stop reading, then you can decide whether to close your end of the socket, or reuse it for a new request.
Have a look at this pseudo code for the type of parsing and reading logic you need to use.
Also, your HTTP request is malformed, as you are not sending a required Host header, so no matter what, you will always receive a 400 Bad Request response from any HTTP 1.1 compliant server:
const char* msg = "GET / HTTP/1.1\r\n"
"Host: www.google.com\r\n" // <-- add this!
"\r\n";
The solution was to shutdown the socket for reading, both in Windows and Linux:
// after sending a request:
shutdown(sock, SD_SEND); // or 'SHUT_WR' in Linux
// now read loop
Curiously, 'shutdown' was called in Winsock tutorials too, but I thought that was unnecessary.

Extract data (string, char, etc.) from an incoming stream on a C socket

How do I extract the actual data (in a form of human readable string, character, an integer etc.) from an incoming stream on a socket in C? The point of this is to be able to act on the contents of the incoming message.
struct netconn *client = NULL;
struct netconn *nc = netconn_new(NETCONN_TCP);
netconn_bind(nc, IP_ADDR_ANY, 8569);
netconn_listen(nc);
while (1) {
err_t err = netconn_accept(nc, &client);
if (err == ERR_OK) {
struct netbuf *nb;
if ((err = netconn_recv(client, &nb)) == ERR_OK) {
/* INTERPRETE INCOMING DATA HERE?? */
}
netbuf_delete(nb);
}
netconn_close(client);
netconn_delete(client);
}
The client connects and sends, say 'testing123' string. How do I go about interpreting this string on the 'server' side?
The point of this exercise is to be able to trigger desired behaviour on the receiving end with the use of appropriate 'command' sent across the local network to WLAN-attached ESP8266 microcontroller.
Ps. I realize it's probably very primitive mechanism so I would appreciate some feedback regarding this matter. Any thoughts/ideas/suggestions greatly appreciated.
As your server can't know what and how the data is being send you need to specify a common message or some kind of seperator between words if you choose to use strings.
For example you could use a | as a seperator so that you would input the following on your client: testing|123
On your server you would now need to search for the | seperator and divide the incoming data so you have a string "testing" and a int "123".
As another aproach you could define yourself a interface based on numbers with the help of a struct.
For example:
typedef struct
{
int cmd;
int subCmd;
} cmdStruct;
In this you would need to deserialize the incoming bytes and parse them to the command structure and act upon the received command. This would include that you send the command accordingly.
Trivial excercise as it turns out. The netbuf structure have 'placeholders' for the contents of incoming data and it's lenght;
netbuf_data(nb, &data, &len);
In my case;
/* INTERPRETE INCOMING DATA HERE?? */
void *data;
u16_t len;
netbuf_data(nb, &data, &len);
char * theData = data;
printf("%s\n", theData);
prints the incoming string on-screen.

Knowing when Client has finished reading from the socket in C

I am writing a client-server program in c where I have to send multiple image files from the server to the client. Is there any way for the server to know when the client has finished reading from socket, creating the image file locally, and successfully written to it? P.S. I already tried sending a message to the socket and when I try to read the socket from the server, the program hangs. Any help will be much appreciated.
Here is a function from the Server code which sends the file to socket:
while(1)
{
unsigned char buf[256] = {0};
int n = fread(buf,1,256,fp);
if(n>0) { send(sockfd,buf,n,0); }
if(n<256) {
if(feof(fp))
printf("Sent to socket\n");
break;
}
}
fclose(fp);
}
char buf[5]
read(sockfd,buf,5);
if(strcmp(buf,"ready")==0) //send more files
And here is a function from the client to write to the file:
FILE* fp;
fp = fopen(file_path,"ab");
char buf[256];
int num;
int total=0;
while(( num = recv(sockfd,buf,256,0))>0)
{
total+=num;
fwrite(buf,1,num,fp);
}
fclose(fp);
write(sockfd,"ready",5);
}
When I do a read on the server after one file transfer, the program hangs.
You problem is here in the client:
while(( num = recv(sockfd,buf,256,0))>0)
recv() will only return 0 at end-of-file - ie when the server shuts down the sending side of the socket. However your server isn't doing that - it's waiting for a response from the client. This means you deadlock.
If you want to send multiple images in the one connection, you need to send your client some information to allow it to tell when one image ends. One way to do this is to first send your client the size of the file it should expect, then the file data. The client can then keep track of how many bytes it's recieved, and send the "ready" reponse after that.
You need a kind of protocol to allow :
the server to tell the client that all has been written
the client to tell the server that all has been read
If you only send one file, the simplest way is to use shutdown(sockfd, SHUT_WR) server side after all data has beed sent. That way the client will get a 0 as return from recv signaling end of data and will be able to send its acknowledgement. But you can no longer write on the socket server side.
If you want to be able to send more than one file, you will have to imagine a cleverer protocol. A common one would be to send blocs of data preceded by their size
short sz = htons(n); /* deals with possible endianness problems */
send(sockfd, &sz, sizeof(short), 0)
send(sockfd, buf, n);
And a sz == 0 (with no buf ...) would signal end of data
This would still be a simple protocol with no error recovery, but at least it can work when no incident happens.

how read all the server's responses from a socket?

I have a very big problem... I'm working with sockets in C. I send a request to the server which sends me many responses. The problem is that the client receives the first response and then the connection is closed. What can I do? I tried with setsockopt()... SO_KEEPALIVE or SO_LINGER but I haven't resolved the problem. Can you help me? Thanks a lot
To be more clear here is the code. The socket is automatically closed after a certain amount of time or after the client received the first response... I'm not sure.
char* demarre_client( client_args * c_args,char* message, /*char* SERVEUR_PORT*/int port){
int socket_client=socket(PF_INET,SOCK_STREAM,0);
memset(&(c_args->adresse_serveur),0,sizeof(c_args->adresse_serveur));
c_args->adresse_serveur.sin_family=AF_INET;
c_args->adresse_serveur.sin_addr.s_addr=inet_addr(SERVEUR_IP);
//int port=APHash(SERVEUR_PORT,strlen(SERVEUR_PORT));
c_args->adresse_serveur.sin_port=htons(port);
int err=0;
if ((err=connect(socket_client, (struct sockaddr *) &(c_args->adresse_serveur), sizeof(c_args->adresse_serveur)))<0)
{
printf("CONNECT error %d\n", errno);
exit(-1);
}
if (send(socket_client, message, strlen(message), 0)!=strlen(message))
{
printf("send error!!\n");
exit(-2);
}
char* raspFin=(char* )malloc(sizeof(char)*1024);
strcpy(raspFin,"");
int num=-1;
int nn=0;
char* rasp=(char* )malloc(sizeof(char)*1024);
memset (rasp, 0, 1024 * sizeof(char ));
/* here it reads the first response and after he get out of while */
while ((num=recv(socket_client, rasp,1024,MSG_WAITALL))>0)
{
printf("recu %s mun=%d\n" , rasp,num);
strcat(raspFin,rasp);
strcat(raspFin,"\n");
rasp=(char* )malloc(sizeof(char)*1024);
memset (rasp, 0, 1024 * sizeof(char ));
}
if (num<0)
{
printf("rasp error!!\n");
exit(-3);
}
Are you sure you don't get all responses on first call?
TCP/IP is stream protocol without flow control built-in so different messages, sent using separate send() calls, can be received in one recv(). Because you use printf(), it prints the buffer until it sees null-terminator - maybe other responses beyond the terminator?
Try to use some flow control, like sending message length prefix or using some special characters (like STX/ETX, but make sure your message doesn't contain such characters). You'd need to implement some flow-control anyway if you plan to use this software.
For now try replacing your printf() with
char *ptr;
for (ptr = buffer; ptr <= buffer + num; ptr += strlen(ptr)+1;)
printf("%s\n", ptr);
It will print all strings from your response buffer.
And you don't need malloc() inside the loop - you leak memory.
BTW SO_KEEPALIVE and SO_LINGER have nothing to do with this problem.
My suggestion would be to fire up Wireshark network analyzer and see what's happening packet-wise. In filters set
tcp.srcport == <insert_server_port> || tcp.dstport == <insert_server_port>
You should see what data actually gets sent to and who closes the connection (sends FIN/RST packets).

Resources