Author Topic: Simple reliable UDP send and receive  (Read 4863 times)

0 Members and 1 Guest are viewing this topic.

Offline Neea

  • Peasant
  • *
  • Posts: 83
  • Cookies: 19
  • Laboris Gloria Ludi
    • View Profile
Simple reliable UDP send and receive
« on: May 30, 2013, 01:25:15 pm »
Hey guys, this is my own pretty basic implementation of a reliable send and receive over UDP. I was supposed to follow a certain protocol i was given, but screwed it up on that but regardless, the functions work xD. Also if you want to implement a concurrent server, the connection state structure should be wrapped in a map or a list so that for every IP:PORT connection there is an individual connection state. It can probably be done easier with classes and objects than using regular structures.
Sorry if my code is messy, i'm still learning :)



Header and source files:
Code: (c) [Select]



/*
 * RelLib.h
 *
 *  Created on: May 24, 2013
 *      Author: neea
 */


#ifndef RELLIB_H_
#define RELLIB_H_


#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <queue>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/types.h>


const int MAXPKTSIZE = 1024;
const int MAXQUEUESIZE = 5 * MAXPKTSIZE;
const int RETRYTIMEOUT = 500;
const int MAXRETRY = 20;
#define UINT32_MAX 4294967295U


using namespace std;


struct packet{
uint32_t sequenceNo;
uint16_t payloadLen;
uint16_t ackFlag;
uint32_t ack;
char payloadData[MAXPKTSIZE];
};


struct connectionState{
uint32_t sequenceNo;
uint32_t expectedSequenceNo;
int retryNo;
queue<char> receiveQueue;
};


void init();
int reliableSend(int sock, void* buffer,size_t bufflen,const struct sockaddr *dest_addr, socklen_t destlen);
int reliableRecv(int sock,void* buffer,size_t bufflen,struct sockaddr *src_addr, socklen_t *srclen);


#endif /* RELLIB_H_ */


Code: (c) [Select]



/*
 * RelLib.cpp
 *
 *  Created on: May 24, 2013
 *      Author: neea
 */


#include "RelLib.h"
connectionState css;


void init(){
css.sequenceNo=0;
css.expectedSequenceNo=0;
css.retryNo=0;
}


unsigned int generateError(int err_ratio, unsigned char israndom) {
static int count =0;
//using pure random 0 generation here. err_ratio doesn't count
if (israndom) {
if (count==0) srandom( time(NULL) );
count++;
return random() % 2;
}
int result;
// constant 1 only if err_ratio=0 and israndom=false
if (err_ratio == 0 )
result= 1;
else
// generate 0 with a err_ratio percentage
result = count % err_ratio?1:0;
count++;
return result;
}


int packetSend(int sock, packet p, const struct sockaddr *destAddr, socklen_t destlen){
unsigned int err;
// this returns 1 if called with 0,0 or one 0 every ratio nr if called with nr,0
err = generateError(3,0);
printf("Payload data send:number %d, length: %d and ack: %d ", p.sequenceNo, p.payloadLen,p.ack);
if (err) {
int n;
printf("\n");
n= sendto(sock, &p, sizeof(packet), 0, destAddr, destlen);


return n;
} else{
printf("LOST");
printf("\n");
return 0;
}
printf("\n");
return 0;


}


int packetReceive(int sockfd, packet &p,struct sockaddr *sourceAddr, socklen_t *sourcelen){
int r = recvfrom(sockfd, &p, sizeof(packet), 0, sourceAddr, sourcelen);
if(p.ackFlag==1)
printf("Payload data received with ack:number %d and length: %d and ack val: %d\n", p.sequenceNo, p.payloadLen, p.ack);
else printf("Payload data received:number %d and length: %d\n", p.sequenceNo, p.payloadLen);
return r;
}


int reliableSend(int sock, void* buffer,size_t bufflen,const struct sockaddr *dest_addr, socklen_t destlen){
int sendSize =0, selectVal;
packet p;
timeval tv;
fd_set fdset;
p.sequenceNo=css.sequenceNo;
p.ack=0;
p.ackFlag=0;
if(bufflen - sendSize > MAXPKTSIZE) p.payloadLen=MAXPKTSIZE;
else p.payloadLen = (bufflen - sendSize);
memcpy(&(p.payloadData), (char*)buffer + sendSize, p.payloadLen);
tv.tv_sec = 0;
tv.tv_usec =RETRYTIMEOUT*1000;
while(sendSize < bufflen){
packetSend(sock, p, dest_addr, destlen);
FD_ZERO(&fdset);
FD_SET(sock, &fdset);
selectVal = select(sock+1, &fdset, NULL, NULL, &tv);
if (selectVal == -1) {
printf("SEND : Select Error!\n");
return -1;
}




if(selectVal == 0){
css.retryNo++;
printf("Resend :  because timeout : %d!\n", css.retryNo);
//if maxretry return error reliableSend
if (css.retryNo == MAXRETRY) {
return -1;
}
continue;
}else{


packet reciv;
packetReceive(sock,reciv,NULL,NULL); //!!!!!!
if(reciv.ackFlag==1){
if(reciv.ack==css.sequenceNo+1){
if(css.sequenceNo == UINT32_MAX){
return -1;
}
css.sequenceNo++;
//cout << "Seq no after ack =1 " << recvp.sequenceNo<<endl;
css.expectedSequenceNo++;
css.retryNo = 0;
sendSize += p.payloadLen;
//move to next packet
p.ackFlag = 0;
p.ack = 0;
p.sequenceNo = css.sequenceNo;
if(bufflen - sendSize > MAXPKTSIZE) p.payloadLen=MAXPKTSIZE;
else p.payloadLen = (bufflen - sendSize);
memcpy(&p.payloadData, (char*)buffer + sendSize, p.payloadLen);
}
else{
if(reciv.ack==css.sequenceNo){
cout <<"Sleeping " << endl;
usleep(RETRYTIMEOUT);
continue;
}
else{
if(reciv.ack> css.expectedSequenceNo){
css.retryNo++;
usleep(RETRYTIMEOUT);
if (css.retryNo == MAXRETRY) {
return -1;
}


}
}
}
}
else{
cout << "No ack flag!" <<endl;
}
}
}
return 0;


}


int reliableRecv(int sock, void *buffer, size_t bufflen, struct sockaddr *src_addr, socklen_t *srclen) {
int receivedSize=0;
packet reciv;
while (receivedSize < bufflen) {
if (css.receiveQueue.size() > 0) {
int len;
if(css.receiveQueue.size()<bufflen) len = css.receiveQueue.size();
else len = bufflen;
//getting data out of the queue into the buffer
for (int i = 0; i < len; i++) {
((char*)buffer)[i+receivedSize] = css.receiveQueue.front();
css.receiveQueue.pop();
}
} else {
packetReceive(sock,reciv,src_addr, srclen);
if(reciv.sequenceNo == css.expectedSequenceNo){
if (css.receiveQueue.size() >= MAXQUEUESIZE) {
packet p;
p.sequenceNo=css.sequenceNo;
p.ackFlag = 1;
p.ack = css.expectedSequenceNo;
p.payloadLen = 0;
int k = sizeof(struct sockaddr);
printf("RCV-got queue size = maxpacketsize!\n");
packetSend(sock, p, src_addr, k);
} else {
for (int i = 0; i < reciv.payloadLen; i++) {
css.receiveQueue.push(reciv.payloadData[i]);
}
css.expectedSequenceNo++;
packet p;
p.ackFlag = 1;
p.sequenceNo=css.sequenceNo++;
p.ack = css.expectedSequenceNo;
p.payloadLen = 0;
int k = sizeof(struct sockaddr);
int ret;
while((ret = packetSend(sock, p, src_addr, k)) == 0);
int len;
if(css.receiveQueue.size()< bufflen) len = css.receiveQueue.size();
else len = bufflen;
for (int i = 0; i < len; i++) {
((char*)buffer)[i+receivedSize] = css.receiveQueue.front();
css.receiveQueue.pop();
}
receivedSize += reciv.payloadLen;
if (reciv.payloadLen < MAXPKTSIZE)
return receivedSize;
}
}
else{
packet p;
p.ackFlag = 1;
p.sequenceNo=css.sequenceNo;
p.ack = css.expectedSequenceNo;
int k = sizeof(struct sockaddr);
packetSend(sock, p, src_addr, k);


}
}
}
return receivedSize;
}
« Last Edit: May 30, 2013, 06:38:53 pm by Neea »
<!--Here be Cthulhu -->

Offline Stackprotector

  • Administrator
  • Titan
  • *
  • Posts: 2515
  • Cookies: 205
    • View Profile
Re: Simple reliable UDP send and receive
« Reply #1 on: May 30, 2013, 01:29:01 pm »
There is this thing called TCP who is invented to be reliable. Why should you try to do this ?:P
~Factionwars

Offline bluechill

  • Cybermancer
  • Royal Highness
  • ****
  • Posts: 682
  • Cookies: 344
  • I am the existence in these walls
    • View Profile
Re: Simple reliable UDP send and receive
« Reply #2 on: May 30, 2013, 02:20:32 pm »
By definition UDP isn't reliable.  It's supposed to be a method where you can have "fire and forget" packets and of they're dropped, that's okay.  TCP on the other hand guarantees that your packets will get there and in a sequential order but it could be slower and if you're in a game, while you're waiting for packets to get there, stuff could be going on so you can't use the new packets yet.  This is why games use UDP most often.
I have dreamed a dream, but now that dream has gone from me.  In its place now exists my own reality, a reality which I have created for myself by myself.

Offline Neea

  • Peasant
  • *
  • Posts: 83
  • Cookies: 19
  • Laboris Gloria Ludi
    • View Profile
Re: Simple reliable UDP send and receive
« Reply #3 on: May 30, 2013, 02:29:11 pm »
There is this thing called TCP who is invented to be reliable. Why should you try to do this ? :P


1. for learning purposes
2. there are plenty of applications that prefer reliable udp, over tcp just to get rid of the overhead the 3-way hand shake creates
3. probably other more complex reasons i don't know about, taking in consideration that there are plenty of complex implementations for reliable udp (and i think most DNS servers actually have that)
<!--Here be Cthulhu -->

Offline bluechill

  • Cybermancer
  • Royal Highness
  • ****
  • Posts: 682
  • Cookies: 344
  • I am the existence in these walls
    • View Profile
Re: Simple reliable UDP send and receive
« Reply #4 on: May 30, 2013, 02:58:33 pm »
2. there are plenty of applications that prefer reliable udp, over tcp just to get rid of the overhead the 3-way hand shake creates

There is no such thing as reliable UDP.  If you want reliable use TCP.  If you truly want to make a reliable protocol, just recreate TCP using raw packets but don't use UDP and make a mess out of its purpose, unreliable communication.

"UDP uses a simple transmission model with a minimum of protocol mechanism.[1] It has no handshaking dialogues, and thus exposes any unreliability of the underlying network protocol to the user's program. As this is normally IP over unreliable media, there is no guarantee of delivery, ordering or duplicate protection." ~ Wikipedia
I have dreamed a dream, but now that dream has gone from me.  In its place now exists my own reality, a reality which I have created for myself by myself.

Offline Neea

  • Peasant
  • *
  • Posts: 83
  • Cookies: 19
  • Laboris Gloria Ludi
    • View Profile
Re: Simple reliable UDP send and receive
« Reply #5 on: May 30, 2013, 03:06:55 pm »
There is no such thing as reliable UDP.  If you want reliable use TCP.  If you truly want to make a reliable protocol, just recreate TCP using raw packets but don't use UDP and make a mess out of its purpose, unreliable communication.

"UDP uses a simple transmission model with a minimum of protocol mechanism.[1] It has no handshaking dialogues, and thus exposes any unreliability of the underlying network protocol to the user's program. As this is normally IP over unreliable media, there is no guarantee of delivery, ordering or duplicate protection." ~ Wikipedia


Quote
"In computer networking, the Reliable User Datagram Protocol (RUDP) is a transport layer protocol designed at Bell Labs for the Plan 9 operating system. It aims to provide a solution where UDP is too primitive because guaranteed-order packet delivery is desirable, but TCP adds too much complexity/overhead. In order for RUDP to gain higher Quality of Service, RUDP implements features that are similar to TCP with less overhead.

In order to ensure quality, it extends UDP by means of adding the following features:
Acknowledgment of received packets
Windowing and flow control
Retransmission of lost packets
Overbuffering (Faster than real-time streaming)
RUDP is not currently a formal standard, however it was described in an IETF internet-draft in 1999. It has not been proposed for standardization.


Microsoft has introduced another protocol which it named R-UDP and uses it in its MediaRoom product for IPTV service delivery over multicast networks. This is a proprietary protocol and very little is known about its operation. It is not thought to be based on the above referenced IETF draft.
" ~Wikipedia




:)
<!--Here be Cthulhu -->

Offline proxx

  • Avatarception
  • Global Moderator
  • Titan
  • *
  • Posts: 2803
  • Cookies: 256
  • ФФФ
    • View Profile
Re: Simple reliable UDP send and receive
« Reply #6 on: May 30, 2013, 05:46:12 pm »
I think its kinda interesting to do this.
In fact thought about doing this myself.

Even if its just for learning purpose.
Wtf where you thinking with that signature? - Phage.
This was another little experiment *evillaughter - Proxx.
Evilception... - Phage

Offline s3my0n

  • Knight
  • **
  • Posts: 276
  • Cookies: 58
    • View Profile
    • ::1
Re: Simple reliable UDP send and receive
« Reply #7 on: May 30, 2013, 06:29:08 pm »
The UDP datagram is smaller than TCP segment, so it would transfer faster over a network. For reliable UDP implementations look for example at TFTP, which uses UDP to transfer files, and as you know in file transfer the aim is to get the original file's bits be exactly the same as the transferred file bits.

Oh yeah, and please use code=c in square brackets instead of just code, for syntax highlighting :P
« Last Edit: May 30, 2013, 06:35:13 pm by s3my0n »
Easter egg in all *nix systems: E(){ E|E& };E

Offline Neea

  • Peasant
  • *
  • Posts: 83
  • Cookies: 19
  • Laboris Gloria Ludi
    • View Profile
Re: Simple reliable UDP send and receive
« Reply #8 on: May 30, 2013, 06:42:31 pm »
The UDP datagram is smaller than TCP segment, so it would transfer faster over a network. For reliable UDP implementations look for example at TFTP, which uses UDP to transfer files, and as you know in file transfer the aim is to get the original file's bits be exactly the same as the transferred file bits.

Oh yeah, and please use code=c in square brackets instead of just code, for syntax highlighting :P


Edited :)
Yes the application that ran this reliable library i implemented had the purpose of transferring a file with no packet loss, but i haven't posted it because it's a simple server/client implemented the same way as you do with normal UDP, but uses reliableSend and reliableRecv instead of sendto and recvfrom
« Last Edit: May 30, 2013, 06:43:28 pm by Neea »
<!--Here be Cthulhu -->

Offline kenjoe41

  • Symphorophiliac Programmer
  • Administrator
  • Baron
  • *
  • Posts: 990
  • Cookies: 224
    • View Profile
Re: Simple reliable UDP send and receive
« Reply #9 on: May 30, 2013, 09:44:16 pm »
I think its worth a try to code this for learning purposes, you never know what you will need it for tomorrow. In fact am going to try it in python first time am free.
If you can't explain it to a 6 year old, you don't understand it yourself.
http://upload.alpha.evilzone.org/index.php?page=img&img=GwkGGneGR7Pl222zVGmNTjerkhkYNGtBuiYXkpyNv4ScOAWQu0-Y8[<NgGw/hsq]>EvbQrOrousk[/img]

Offline bluechill

  • Cybermancer
  • Royal Highness
  • ****
  • Posts: 682
  • Cookies: 344
  • I am the existence in these walls
    • View Profile
Re: Simple reliable UDP send and receive
« Reply #10 on: May 31, 2013, 04:35:13 am »


:)

Like I said.  UDP is not reliable.  There is no such thing as a reliable version of UDP.  There is however a *modified* version of UDP which is no longer UDP called RUDP.  There is a difference.  If you mean RUDP say RUDP not reliable UDP.  By saying Reliable UDP most people think you won't know what you're talking about because UDP is not reliable.  It's a fine line but you should be careful in your explanations because computer science has a lot of them.
I have dreamed a dream, but now that dream has gone from me.  In its place now exists my own reality, a reality which I have created for myself by myself.

Offline Neea

  • Peasant
  • *
  • Posts: 83
  • Cookies: 19
  • Laboris Gloria Ludi
    • View Profile
Re: Simple reliable UDP send and receive
« Reply #11 on: May 31, 2013, 06:40:58 am »
Like I said.  UDP is not reliable.  There is no such thing as a reliable version of UDP.  There is however a *modified* version of UDP which is no longer UDP called RUDP.  There is a difference.  If you mean RUDP say RUDP not reliable UDP.  By saying Reliable UDP most people think you won't know what you're talking about because UDP is not reliable.  It's a fine line but you should be careful in your explanations because computer science has a lot of them.


Google says reliable UDP = RUDP (which actually reads like reliable user datagram protocol). And what i implemented is not RUDP, it's a light version of a reliable user datagram protocol (if it makes a difference that i actually write it extended). Also if Mozilla for example gets 100 add-ons, you don't call it google chrome, just saying :)
<!--Here be Cthulhu -->

Offline techb

  • Soy Sauce Feeler
  • Global Moderator
  • King
  • *
  • Posts: 2350
  • Cookies: 345
  • Aliens do in fact wear hats.
    • View Profile
    • github
Re: Simple reliable UDP send and receive
« Reply #12 on: May 31, 2013, 06:54:25 am »
UDP was never meant for file transfer. UDP is for things that can handle packet loss such as streaming video. If it can handle things missing and keep going, then use it. If data being lost means corruption, then go TCP. UPD is there for a reason, if you try and implement too much check sums and data corrections then what is the point? There are other protocols for such a thing.
>>>import this
-----------------------------

Offline s3my0n

  • Knight
  • **
  • Posts: 276
  • Cookies: 58
    • View Profile
    • ::1
Re: Simple reliable UDP send and receive
« Reply #13 on: May 31, 2013, 08:06:18 am »
By saying Reliable UDP most people think you won't know what you're talking about because UDP is not reliable.  It's a fine line but you should be careful in your explanations because computer science has a lot of them.

It's quite the opposite. By saying *reliable* UDP, you are saying that you know UDP is not reliable, and that you are talking about some mechanism built on top of UDP to make it reliable.
But if you say reliable TCP then they might think you don't know what you are talking about because TCP is already reliable.
Easter egg in all *nix systems: E(){ E|E& };E

Offline Neea

  • Peasant
  • *
  • Posts: 83
  • Cookies: 19
  • Laboris Gloria Ludi
    • View Profile
Re: Simple reliable UDP send and receive
« Reply #14 on: May 31, 2013, 10:02:38 am »
UDP was never meant for file transfer. UDP is for things that can handle packet loss such as streaming video. If it can handle things missing and keep going, then use it. If data being lost means corruption, then go TCP. UPD is there for a reason, if you try and implement too much check sums and data corrections then what is the point? There are other protocols for such a thing.


I wasn't the one to invent reliable user datagram protocol and i am pretty much guessing there was quite a good reason for it to appear, i don't think the networks guys thought "Hmm this looks fun to implement, lets try it for the heck of it". Also taking in consideration the evolution of internet and networking, it might perhaps seem a bit pointless now, but in the past RUDP might have been useful, but mostly for specific implementations (because it's not something you can use on a wide application scale) one of the reasons why it's not a standard.


Why did i implement it?
- because it was good practice and helped me understand better udp, packet transmission, and showed me a less complex solution for something similar to tcp.
- it gives you control over the packets you send (and trust me i wouldn't try to implement my own variant of tcp) .... so for learning purposes it's great exercise
- because i could


Now honestly i would have expected more comments on the content (aka code) than on the reason why i decided to implement this.

<!--Here be Cthulhu -->