This is more of a conceptual confusion. I am making a multicast server which just echoes back the datagram received.Here's the code
while (1) {
cnt = recvfrom(sock, message, sizeof(message), 0,
(struct sockaddr *) &addr, &addrlen);
//printf("%d \n",cnt);
if (cnt < 0) {
perror("recvfrom");
exit(1);
} else if (cnt == 0) {
break;
}
printf("%s: message = \"%s\"\n", inet_ntoa(addr.sin_addr), message);
addr.sin_addr.s_addr = inet_addr(EXAMPLE_GROUP);
cnt = sendto(sock, message, sizeof(message), 0,
(struct sockaddr *) &addr, addrlen);
if (cnt < 0) {
perror("sendto");
exit(1);
}
}
The problem with this is as a multicast server will also receive the datagram. So, after it recieves a datagram, it sends, it again recieves the same datagram, and so on entering an infinite loop. Any pointers on how to implement such type of server?
You need to disable multicast loopback via setsockopt().
One option is what EJP said, to disable multicast loopback so that the sending machine doesn't receive a copy of its own multicast packet back. However, be aware that if you do that, you won't be able to test with clients and server all running on the same machine anymore, since IP_MULTICAST_LOOP is implemented at the IP routing level.
A second possible option to avoid infinite packet loops would be to have the echo-server send its response packets to a different multicast group than the one it listens on (or even have it send its responses via unicast rather than multicast; the server could call recvfrom() to find out the unicast source address of any packet it receives, so it's easy for it to know where to send the reply packet back to)
A third option would be to modify the contents of the packet somehow to mark it as already-seen, so that your server knows not to echo it a second time. For example, you could specify that your server will only echo packets whose first byte is set to zero, and when your server echoes a packet, it makes sure to set the packet's first byte to one before send()-ing it out. (Your clients would need to be aware of this convention, of course)
Related
I am searching for a long time on net. But no use. Please help or try to give some ideas how to achieve this.
I have finished writing the program, and today when I tested the ping loopback address, after sending the packet, the function recvfrom() received the "first" packet (type 8), and the second recvfrom() received the response packet (type 0).
It was later discovered that the type value for the odd times was 8 and the type value for the even times was 0.
The actual packets I caught with Wireshark have corresponding response packets each time, but the first time received by recvfrom() are the outgoing packets.
// Send
if (sendto(sockfd, &sendicmp, ICMP_SIZE, 0, (struct sockaddr *) &to, sizeof(to)) == -1) {
printf("sendto() error \n");
continue;
}
// Receive
struct timeval timeout = {3, 0};//3s
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
if ((n = recvfrom(sockfd, buf, BUF_SIZE, 0, (struct sockaddr *) &from, &fromlen)) < 0) {
printf("Time out! \n");
continue;
}
nreceived++;
if (unpack(buf, n) == -1) {
printf("unpack() error \n");
}
enter image description here
Since the type value is not 0, I let the output is not the ICMP packet sent to me
An ICMP type 8 control message is an echo request. A type 0 is an echo reply. Thus, it sounds like your program is receiving its own requests in addition to the replies to those requests. That is natural if you are successfully pinging a loopback address, because that's how loopback works.
It's less of an issue for TCP and UDP, because these protocols provide a concept of ports on top plain IP to distinguish between different applications communicating via the same address. ICMP does not have that, so it is the responsibility of a process receiving ICMP messages to perform its own message filtering. A ping program in particular would probably ignore incoming ICMP messages other than echo replies (type 0). It might furthermore use the second four octets of the ICMP header to distinguish replies to its own echo requests from replies to other programs running at the same time.
Just for the purpose of learning raw sockets in C I am writing a simple server that uses raw sockets to receive and send messages.
I create the socket
if ((r_sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP))< 0){
perror("socket");
exit(-1);
}
Then I create an infinite loop and start receiving, processing, and replying
while(1){
if((n = recvfrom(r_sock, buffer, BUFLEN, 0, (struct sockaddr *) &client, &client_len))<0){
perror("recvfrom");
exit(-1);
}
// Discard messages not intended to the server
if(htons(udp->uh_dport) != my_port){
continue;
}
//Do whatever with the data received and then send reply to client
// ....
if((n = sendto(r_sock, udp, ntohs(udp->uh_len), 0, (struct sockaddr *) &client, client_len))<0){
perror("sendto");
exit(-1);
}
}
I am not showing here the definition of every single variable but for the sake of completeness, buffer is a char array of size BUFLEN (big enough) and udp is a struct udphdr pointer to the right position in the buffer.
The point is that I have another program that serves as client using standard UDP sockets (SOCK_DGRAM) which is proved to be working properly (I also tried with netcat just in case). When I send a message with the client, it never receives the reply back. It seems that when the server sends the reply to the client, the server itself gets the message and the client gets nothing.
So, my question is: is there a way of solving this with raw sockets? That is, to make the server not receive its own messages and preventing others from receiving them?
Thanks in advance!
I have just realised that it was a problem with the checksum... Once I had a correct checksum in UDP the packet was correctly received by the client.
Wireshark gave me the lead to the solution. I saw that the checksum was not validated so I went to Edit > Preferences > Protocols > UDP > Validate the UDP checksum if possible and checked it.
Hope it helps
I have been working on how to transfer an image using UDP in C, I have created a code that sometimes works, sometimes it doesn't. In what I think the issue is that sometimes the server receives more packages than writes. I know that I am trying to create the TCP, but that is what I am kind looking for, but not sure how to do it.
I think to fix it the client should send the buff of the img and only sends the second part when the server reply back to the client.
Here is the code:
Client:
while (!feof(p))
{
fread(*&c, 1, BLEN, p);
sprintf(buf, "%s", *&c);
temp=sendto(s,buf,BLEN, 0, (struct sockaddr *) &si_other, slen);
//sleep(3);
//printf("%d ",temp);
if(temp < 0)
{
fprintf(stderr,"sendto error.\n");
printf("erro");
exit(1);
}
i++;
}
Server:
while(1){
if(recvfrom(s, buf, BLEN, 0, (struct sockaddr *) &si_other, (unsigned int *) &slen)==-1){
perror("recvfrom error.\n");
exit(1);
}
//printf("%s ", &si_other);
flagr[0] = buf[0];
flagr[1] = buf[1];
flagr[2] = buf[2];
if (strcmp(flagr, flag) == 0 ){
break;
}
fwrite(buf, 1, BLEN, pp);
i++;
}
UDP is a datagram protocol, meaning that each call to sendto sends one message. If that message is larger than an IP packet can hold, it will be fragmented across multiple IP datagrams. If any one of those fragments fails to arrive, the whole thing is dropped at the OS level.
The data needs to be sent in chunks of no more than about 1450 bytes. Then the receiving side will need to read each packet and, because UDP does not guarantee that data will arrive in order, you will need to reassemble them in the proper order.
That means each packet has to have a user-defined header which contains the sequence number so that the receiver knows what order to put them in.
You also need to worry about retransmissions, since UDP doesn't guarantee that a packet that is send is actually received.
There's a program I wrote called UFTP which does all of this. Take a look at the documentation and code to get an idea of what you need to do to implement reliable data transfer over UDP.
Currently implementing a TCP socket in C. Using libcurl I am sending a HTTP POST request with some XML files. The connection and transmission is working correctly.
Now, when I try to send 2 different XML files in the same session to the server I always get the value of the first transmission I sent. Meaning I always get the old value, the socket does not give back the new value received on the socket.
Wireshark shows me that the different XML files are transmitted. Do I need to clean the socket somehow after each TCP connection has been made?
Here is my server implementation:
while (1) {
char buf[512];
connfd = accept(listenfd, (struct sockaddr*) NULL, NULL);
if (connfd == -1) {
perror("accept");
continue;
}
int rec;
rec = recv(connfd, buf, sizeof (buf), 0);
printf ("Receive val: %d\n", rec);
//DO STUFF
//Send back ACK
strcpy(sendBuff, "Received");
write(connfd, sendBuff, strlen(sendBuff));
close(connfd);
sleep(1);
}
you close the session right after the first packet is received. This is why you don't get the next packet.
You should handle each incoming connection in a separate thread, or make sure somehow before you close the socket, that no more incoming data should arrive
I'm working on a homework problem for class. I want to start a UDP Server that listens for a file request. It opens the file and sends it back to the requesting client with UDP.
Heres the server code.
// Create UDP Socket
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Can't create socket");
exit(-1);
}
// Configure socket
memset(&server, 0, sizeof server);
server.sin_family = AF_INET; // Use IPv4
server.sin_addr.s_addr = htonl(INADDR_ANY); // My IP
server.sin_port = htons(atoi(argv[1])); // Server Port
// Bind socket
if ((bind(sockfd, (struct sockaddr *) &server, sizeof(server))) == -1) {
close(sockfd);
perror("Can't bind");
}
printf("listener: waiting to recvfrom...\n");
if (listen(sockfd, 5) == -1) {
perror("Can't listen for connections");
exit(-1);
}
while (1) {
client_len = sizeof(struct sockaddr_in);
newsockfd = accept(sockfd, (struct sockaddr*)&client,&client_len);
if (newsockfd < 0) {
perror("ERROR on accept");
}
// Some how parse request
// I do I use recv or recvfrom?
// I do I make new UDP socket to send data back to client?
sendFile(newsockfd, filename);
close(newsockfd);
}
close(sockfd);
I'm kind of lost how do I recv data from the client? And how to I make a new UDP connection back to the client?
How UDP is different from TCP:
message-oriented, not stream-oriented. You don't read/write or send/recv. You sendto/recvfrom. The size of message is limited to 64K. Each call to recvfrom gets one message sent by a call to sendto. If recvfrom passes a buffer that's smaller than the size of message, the rest of message is gone for good.
no connections. Therefore no listen/accept/connect. You send a message to a particular address/port. When you receive message (on the address/port to which your socket is bound), you get the source of the incoming message as an output parameter to recvfrom.
no guarantees. The messages can be dropped or received out of order. If I remember correctly, they cannot be truncated, though.
One last word of caution - you may find yourself re-inventing TCP over UDP. In that case, stop and go back to TCP.
I have written a UDP server-client in C , where the client sends a registration number and the server gives a name as the feedback.
SERVER
0. Variable initialization
1. sock()
2. bind()
3. recvfrom()
4. sendto()
CLIENT
0. gethostbyname()
1. sock()
2. bzero()
4. sendto()
5. recvfrom()
Hope it helps. You can find the example code here udp server/client
accept is only used for connection oriented (STREAM) sockets. UDP is not stream, oriented, so there are no connections and you can't use accept(2) -- it will return EOPNOTSUPP.
Instead, you just read packets directly from the bound service socket (generally using recvfrom(2) so you can tell where thy came from, though you can use recv or just read if you don't care), afterwhich you can send packets back using the same socket (and generally using sendto(2))
Keep in mind that UDP is connectionless. It only sends packets, and is not suitable for sending files - unless the entire content fit in one UDP packet.
If you anyway want to send/receive UDP packets, you simply call sendto/recvfrom with the appropriate addresses.