Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
emulab-devel
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
143
Issues
143
List
Boards
Labels
Service Desk
Milestones
Merge Requests
6
Merge Requests
6
Operations
Operations
Incidents
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
emulab
emulab-devel
Commits
ce1f4359
Commit
ce1f4359
authored
Aug 26, 2008
by
Pramod R Sanaga
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
User level TCP over UDP, without receive window.
parent
2f648fa5
Changes
2
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
1363 additions
and
0 deletions
+1363
-0
pelab/bw-bottleneck/userland_tcp/udpClient.cc
pelab/bw-bottleneck/userland_tcp/udpClient.cc
+809
-0
pelab/bw-bottleneck/userland_tcp/udpServer.cc
pelab/bw-bottleneck/userland_tcp/udpServer.cc
+554
-0
No files found.
pelab/bw-bottleneck/userland_tcp/udpClient.cc
0 → 100644
View file @
ce1f4359
This diff is collapsed.
Click to expand it.
pelab/bw-bottleneck/userland_tcp/udpServer.cc
0 → 100644
View file @
ce1f4359
#include <iostream>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <pcap.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/if_ether.h>
#include <net/ethernet.h>
#include <netinet/ether.h>
#include <string>
#include <vector>
#include <map>
#include <list>
#define LOCAL_SERVER_PORT 9831
#define MAX_MSG 1500
pcap_t
*
pcapDescriptor
=
NULL
;
char
appAck
[
120
];
unsigned
long
long
milliSec
=
0
;
int
sd
,
rc
,
n
,
flags
;
socklen_t
cliLen
;
struct
sockaddr_in
cliAddr
,
servAddr
,
destAddr
;
using
namespace
std
;
void
handleUDP
(
struct
pcap_pkthdr
const
*
pcap_info
,
struct
udphdr
const
*
udpHdr
,
u_char
*
const
udpPacketStart
,
struct
ip
const
*
ipPacket
);
struct
tcp_info
{
vector
<
unsigned
long
>
recvdPackets
;
unsigned
long
lastInOrderPacket
;
list
<
pair
<
unsigned
long
,
unsigned
long
>
>
sackRanges
;
unsigned
long
highSeq
;
unsigned
long
missingPacketTotal
;
};
map
<
string
,
struct
tcp_info
*>
connectionMap
;
bool
sackCompare
(
pair
<
unsigned
long
,
unsigned
long
>
pair1
,
pair
<
unsigned
long
,
unsigned
long
>
pair2
)
{
if
(
pair1
.
first
<=
pair2
.
first
&&
pair1
.
second
<=
pair2
.
first
)
return
true
;
else
return
false
;
}
unsigned
long
long
getTimeMilli
()
{
struct
timeval
tp
;
gettimeofday
(
&
tp
,
NULL
);
long
long
tmpSecVal
=
tp
.
tv_sec
;
long
long
tmpUsecVal
=
tp
.
tv_usec
;
return
(
tmpSecVal
*
1000
+
tmpUsecVal
/
1000
);
}
int
getLinkLayer
(
struct
pcap_pkthdr
const
*
pcap_info
,
const
u_char
*
pkt_data
)
{
unsigned
int
caplen
=
pcap_info
->
caplen
;
if
(
caplen
<
sizeof
(
struct
ether_header
))
{
printf
(
"A captured packet was too short to contain "
"an ethernet header"
);
return
-
1
;
}
else
{
struct
ether_header
*
etherPacket
=
(
struct
ether_header
*
)
pkt_data
;
return
ntohs
(
etherPacket
->
ether_type
);
}
}
void
pcapCallback
(
u_char
*
user
,
const
struct
pcap_pkthdr
*
pcap_info
,
const
u_char
*
pkt_data
)
{
int
packetType
=
getLinkLayer
(
pcap_info
,
pkt_data
);
if
(
packetType
!=
ETHERTYPE_IP
)
{
printf
(
"Unknown link layer type: %d
\n
"
,
packetType
);
return
;
}
struct
ip
const
*
ipPacket
;
size_t
bytesLeft
=
pcap_info
->
caplen
-
sizeof
(
struct
ether_header
);
if
(
bytesLeft
<
sizeof
(
struct
ip
))
{
printf
(
"Captured packet was too short to contain an IP header.
\n
"
);
return
;
}
ipPacket
=
(
struct
ip
const
*
)(
pkt_data
+
sizeof
(
struct
ether_header
));
int
ipHeaderLength
=
ipPacket
->
ip_hl
;
int
ipVersion
=
ipPacket
->
ip_v
;
if
(
ipVersion
!=
4
)
{
printf
(
"Captured IP packet is not IPV4.
\n
"
);
return
;
}
if
(
ipHeaderLength
<
5
)
{
printf
(
"Captured IP packet has header less than the minimum 20 bytes.
\n
"
);
return
;
}
if
(
ipPacket
->
ip_p
!=
IPPROTO_UDP
)
{
printf
(
"Captured packet is not a UDP packet.
\n
"
);
return
;
}
// Ignore the IP options for now - but count their length.
/////////////////////////////////////////////////////////
u_char
*
const
udpPacketStart
=
(
u_char
*
const
)(
pkt_data
+
sizeof
(
struct
ether_header
)
+
ipHeaderLength
*
4
);
struct
udphdr
const
*
udpPacket
;
udpPacket
=
(
struct
udphdr
const
*
)
udpPacketStart
;
bytesLeft
-=
ipHeaderLength
*
4
;
if
(
bytesLeft
<
sizeof
(
struct
udphdr
))
{
printf
(
"Captured packet is too small to contain a UDP header.
\n
"
);
return
;
}
handleUDP
(
pcap_info
,
udpPacket
,
udpPacketStart
,
ipPacket
);
}
void
init_pcap
(
char
*
ipAddress
)
{
char
interface
[]
=
"eth4"
;
struct
bpf_program
bpfProg
;
char
errBuf
[
PCAP_ERRBUF_SIZE
];
char
filter
[
128
]
=
" udp "
;
// IP Address and sub net mask.
bpf_u_int32
maskp
,
netp
;
struct
in_addr
localAddress
;
pcap_lookupnet
(
interface
,
&
netp
,
&
maskp
,
errBuf
);
//pcapDescriptor = pcap_open_live(interface, BUFSIZ, 0, 0, errBuf);
pcapDescriptor
=
pcap_open_live
(
interface
,
64
,
0
,
0
,
errBuf
);
localAddress
.
s_addr
=
netp
;
printf
(
"IP addr = %s
\n
"
,
ipAddress
);
sprintf
(
filter
,
" udp and dst host %s and dst port 9831 "
,
ipAddress
);
if
(
pcapDescriptor
==
NULL
)
{
printf
(
"Error opening device %s with libpcap = %s
\n
"
,
interface
,
errBuf
);
exit
(
1
);
}
pcap_compile
(
pcapDescriptor
,
&
bpfProg
,
filter
,
1
,
netp
);
pcap_setfilter
(
pcapDescriptor
,
&
bpfProg
);
}
void
UpdateSACKs
(
unsigned
long
seqNum
,
bool
consecutiveSeq
,
struct
tcp_info
*
connInfo
)
{
// Update the SACK ranges.
pair
<
unsigned
long
,
unsigned
long
>
tmpRange
;
tmpRange
.
first
=
seqNum
;
tmpRange
.
second
=
seqNum
;
if
(
!
consecutiveSeq
)
// We have a confirmed hole in the received packets.
{
if
(
connInfo
->
sackRanges
.
size
()
==
0
)
connInfo
->
sackRanges
.
push_back
(
tmpRange
);
else
{
// Find the SACK-range that this packet fits into/extends, merging
// two ranges if necessary.
bool
extendsBlock
=
false
;
// If this packet is after the right end of our last SACK block,
// then it is indicating new packet loss.
if
(
seqNum
>
connInfo
->
sackRanges
.
back
().
second
)
connInfo
->
missingPacketTotal
+=
(
seqNum
-
connInfo
->
sackRanges
.
back
().
second
-
1
);
else
connInfo
->
missingPacketTotal
-=
1
;
list
<
pair
<
unsigned
long
,
unsigned
long
>
>::
iterator
sackIter
=
connInfo
->
sackRanges
.
begin
();
while
(
sackIter
!=
connInfo
->
sackRanges
.
end
())
{
// This packet is the next seqnum after the right most edge
// in this sack block.
if
(
seqNum
==
(
*
sackIter
).
second
+
1
)
{
(
*
sackIter
).
second
++
;
extendsBlock
=
true
;
break
;
}
// This packet is the seqnum right before the left most edge
// in this sack block.
if
(
seqNum
==
(
*
sackIter
).
first
-
1
)
{
(
*
sackIter
).
first
--
;
extendsBlock
=
true
;
break
;
}
sackIter
++
;
}
if
(
!
extendsBlock
)
// Create a new SACK block.
{
connInfo
->
sackRanges
.
push_back
(
tmpRange
);
connInfo
->
sackRanges
.
sort
(
sackCompare
);
}
else
if
(
connInfo
->
sackRanges
.
size
()
>
1
)
// Merge sack blocks if possible.
{
list
<
pair
<
unsigned
long
,
unsigned
long
>
>::
iterator
sackIter
=
connInfo
->
sackRanges
.
begin
();
list
<
pair
<
unsigned
long
,
unsigned
long
>
>::
iterator
advanceIter
=
connInfo
->
sackRanges
.
begin
();
advanceIter
=
++
sackIter
;
sackIter
=
connInfo
->
sackRanges
.
begin
();
while
(
advanceIter
!=
connInfo
->
sackRanges
.
end
())
{
if
((
*
sackIter
).
second
==
((
*
advanceIter
).
first
-
1
))
{
(
*
advanceIter
).
first
=
(
*
sackIter
).
first
;
connInfo
->
sackRanges
.
erase
(
sackIter
++
);
}
else
sackIter
++
;
advanceIter
++
;
}
}
}
}
else
// We received a packet that is advancing the left edge of the window.
{
// If we don't have any outstanding SACK blocks, do nothing.
if
(
connInfo
->
sackRanges
.
size
()
!=
0
)
{
if
(
connInfo
->
sackRanges
.
size
()
==
1
)
{
if
(
connInfo
->
sackRanges
.
front
().
second
==
connInfo
->
lastInOrderPacket
)
{
// Delete this lone SACK block, all the packets have been ACKed.
connInfo
->
sackRanges
.
clear
();
connInfo
->
missingPacketTotal
=
0
;
}
}
else
{
list
<
pair
<
unsigned
long
,
unsigned
long
>
>::
iterator
sackIter
=
connInfo
->
sackRanges
.
begin
();
// Remove the first SACK block if possible.
{
if
(
connInfo
->
lastInOrderPacket
==
connInfo
->
sackRanges
.
front
().
second
)
{
// Delete this SACK block because all packets before its left edge
// have been now ACKed.
connInfo
->
missingPacketTotal
-=
1
;
connInfo
->
sackRanges
.
erase
(
sackIter
);
}
}
}
}
}
}
void
handleUDP
(
struct
pcap_pkthdr
const
*
pcap_info
,
struct
udphdr
const
*
udpHdr
,
u_char
*
const
udpPacketStart
,
struct
ip
const
*
ipPacket
)
{
u_char
*
dataPtr
=
udpPacketStart
+
8
;
unsigned
char
packetType
=
*
(
unsigned
char
*
)(
dataPtr
);
if
(
packetType
==
'0'
)
// This is a udp data packet arriving here. Send an
// application level acknowledgement packet for it.
{
unsigned
long
seqNum
=
*
(
unsigned
long
*
)(
dataPtr
+
1
);
unsigned
long
ackedSeq
=
0
;
struct
tcp_info
*
connInfo
;
string
src_ip_port
;
src_ip_port
=
inet_ntoa
(
ipPacket
->
ip_src
)
;
src_ip_port
+=
":"
;
src_ip_port
+=
ntohs
(
udpHdr
->
source
);
//cout << "Received packet #"<<seqNum<<endl;
if
(
connectionMap
.
find
(
src_ip_port
)
!=
connectionMap
.
end
())
// Established connection.
{
// Look up the connection info.
connInfo
=
connectionMap
[
src_ip_port
];
if
(
seqNum
==
connInfo
->
lastInOrderPacket
+
1
)
// Received the next packet in window
// and ACK as many packets as possible.
{
if
(
connInfo
->
recvdPackets
.
size
()
!=
0
)
// There are future seq. numbered packets
// in the buffer.
{
unsigned
long
curSeq
=
seqNum
;
// Remove all contiguous packets from the buffer.
while
(
connInfo
->
recvdPackets
.
front
()
==
curSeq
+
1
)
{
curSeq
++
;
pop_heap
(
connInfo
->
recvdPackets
.
begin
(),
connInfo
->
recvdPackets
.
end
(),
greater
<
int
>
());
connInfo
->
recvdPackets
.
pop_back
();
}
connInfo
->
lastInOrderPacket
=
curSeq
;
}
else
// This packet advances the right edge of the window by one.
connInfo
->
lastInOrderPacket
++
;
ackedSeq
=
connInfo
->
lastInOrderPacket
+
1
;
UpdateSACKs
(
seqNum
,
true
,
connInfo
);
}
else
if
(
seqNum
<=
connInfo
->
lastInOrderPacket
)
// Redundant packet.
ackedSeq
=
connInfo
->
lastInOrderPacket
+
1
;
else
{
vector
<
unsigned
long
>::
iterator
seqNumIter
=
connInfo
->
recvdPackets
.
end
();
seqNumIter
=
find
(
connInfo
->
recvdPackets
.
begin
(),
connInfo
->
recvdPackets
.
end
(),
seqNum
);
if
(
seqNumIter
==
connInfo
->
recvdPackets
.
end
())
// We haven't seen this packet
// before, put it in the received packet list.
{
connInfo
->
recvdPackets
.
push_back
(
seqNum
);
push_heap
(
connInfo
->
recvdPackets
.
begin
(),
connInfo
->
recvdPackets
.
end
(),
greater
<
int
>
());
ackedSeq
=
connInfo
->
lastInOrderPacket
+
1
;
//printf("Initializing SACK blocks for packet %d, ack = %d\n", seqNum,ackedSeq);
UpdateSACKs
(
seqNum
,
false
,
connInfo
);
}
else
// Redundant packet, doesn't advance the window.
ackedSeq
=
connInfo
->
lastInOrderPacket
+
1
;
}
}
else
// New connection
{
connInfo
=
new
struct
tcp_info
;
connInfo
->
recvdPackets
.
resize
(
0
);
connInfo
->
lastInOrderPacket
=
0
;
connInfo
->
sackRanges
.
resize
(
0
);
connectionMap
[
src_ip_port
]
=
connInfo
;
connInfo
->
highSeq
=
seqNum
;
connInfo
->
missingPacketTotal
=
0
;
if
(
seqNum
!=
connInfo
->
lastInOrderPacket
+
1
)
// This isn't the first packet.
{
connInfo
->
recvdPackets
.
push_back
(
seqNum
);
push_heap
(
connInfo
->
recvdPackets
.
begin
(),
connInfo
->
recvdPackets
.
end
(),
greater
<
int
>
());
connInfo
->
lastInOrderPacket
=
0
;
ackedSeq
=
connInfo
->
lastInOrderPacket
+
1
;
UpdateSACKs
(
seqNum
,
false
,
connInfo
);
}
else
// Received the first packet.
{
connInfo
->
lastInOrderPacket
=
1
;
ackedSeq
=
connInfo
->
lastInOrderPacket
+
1
;
}
}
// Keep track of the highest sequence number received from the sender.
if
(
seqNum
>
connInfo
->
highSeq
)
connInfo
->
highSeq
=
seqNum
;
// Send an ACK for the expected sequence number.
appAck
[
0
]
=
'1'
;
char
numSackRanges
=
(
char
)
0
;
int
packetSize
=
2
+
3
*
sizeof
(
unsigned
long
);
// Limit the maximum number of sack blocks to 5.
if
(
connInfo
->
sackRanges
.
size
()
!=
0
)
{
if
(
connInfo
->
sackRanges
.
size
()
>=
5
)
numSackRanges
=
(
char
)
5
;
else
numSackRanges
=
(
char
)
connInfo
->
sackRanges
.
size
();
}
memcpy
(
&
appAck
[
1
],
&
numSackRanges
,
sizeof
(
char
));
memcpy
(
&
appAck
[
2
],
&
ackedSeq
,
sizeof
(
unsigned
long
));
//cout<<"Sending ACK for seqNum = " << ackedSeq<<endl;
// Send the total of missing packets.
memcpy
(
&
appAck
[
2
+
sizeof
(
unsigned
long
)],
&
connInfo
->
missingPacketTotal
,
sizeof
(
unsigned
long
));
// Also the highest sequence number seen.
memcpy
(
&
appAck
[
2
+
2
*
sizeof
(
unsigned
long
)],
&
connInfo
->
highSeq
,
sizeof
(
unsigned
long
));
if
((
int
)
numSackRanges
!=
0
)
{
// printf("Creating a SACK for packet = %d ^ ", ackedSeq);
packetSize
+=
(
2
*
(
int
)
numSackRanges
*
sizeof
(
unsigned
long
));
unsigned
long
rangeBegin
,
rangeEnd
;
list
<
pair
<
unsigned
long
,
unsigned
long
>
>::
iterator
sackIter
=
connInfo
->
sackRanges
.
begin
();
int
i
=
0
;
while
(
i
<
(
int
)
numSackRanges
&&
(
sackIter
!=
connInfo
->
sackRanges
.
end
()))
{
rangeBegin
=
(
*
sackIter
).
first
;
rangeEnd
=
(
*
sackIter
).
second
;
// printf("%d %d: ", rangeBegin, rangeEnd);
memcpy
(
&
appAck
[
2
+
3
*
sizeof
(
unsigned
long
)
+
2
*
i
*
sizeof
(
unsigned
long
)],
&
rangeBegin
,
sizeof
(
unsigned
long
));
memcpy
(
&
appAck
[
2
+
3
*
sizeof
(
unsigned
long
)
+
(
2
*
i
+
1
)
*
sizeof
(
unsigned
long
)],
&
rangeEnd
,
sizeof
(
unsigned
long
));
i
++
;
sackIter
++
;
}
// printf("\n");
//printf("HighSeq = %u, lostNum = %u\n", connInfo->highSeq, connInfo->missingPacketTotal);
}
else
{
// printf("Sending ACK for packet = %u, received = %u ", ackedSeq,seqNum);
}
// Fill in the IP address & port number.
memcpy
((
char
*
)
&
destAddr
.
sin_addr
.
s_addr
,
(
char
*
)
&
ipPacket
->
ip_src
.
s_addr
,
sizeof
(
ipPacket
->
ip_src
.
s_addr
));
destAddr
.
sin_port
=
udpHdr
->
source
;
int
retval
=
sendto
(
sd
,
appAck
,
packetSize
,
flags
,(
struct
sockaddr
*
)
&
destAddr
,
sizeof
(
destAddr
));
if
(
retval
<
0
)
{
cout
<<
"Send failed for ACK "
<<
ackedSeq
<<
endl
;
exit
(
1
);
}
}
else
if
(
packetType
==
'1'
)
// TODO:This is an udp ACK packet. If it is being sent
// out from this host, do nothing.
{
}
else
{
printf
(
"ERROR: Unknown UDP packet received from remote agent
\n
"
);
return
;
}
}
int
main
(
int
argc
,
char
*
argv
[])
{
char
msg
[
MAX_MSG
];
struct
hostent
*
localHost
;
/* socket creation */
sd
=
socket
(
AF_INET
,
SOCK_DGRAM
,
0
);
if
(
sd
<
0
)
{
printf
(
"%s: cannot open socket
\n
"
,
argv
[
0
]);
exit
(
1
);
}
localHost
=
gethostbyname
(
argv
[
1
]);
if
(
localHost
==
NULL
)
{
printf
(
"ERROR: Unknown host %s
\n
"
,
argv
[
1
]);
exit
(
1
);
}
/* bind local server port */
servAddr
.
sin_family
=
AF_INET
;
servAddr
.
sin_family
=
localHost
->
h_addrtype
;
memcpy
((
char
*
)
&
servAddr
.
sin_addr
.
s_addr
,
localHost
->
h_addr_list
[
0
],
localHost
->
h_length
);
servAddr
.
sin_port
=
htons
(
LOCAL_SERVER_PORT
);
rc
=
bind
(
sd
,
(
struct
sockaddr
*
)
&
servAddr
,
sizeof
(
servAddr
));
if
(
rc
<
0
)
{
printf
(
"%s: cannot bind port number %d
\n
"
,
argv
[
0
],
LOCAL_SERVER_PORT
);
exit
(
1
);
}
// Prepare the structure to be used for ACKs.
destAddr
.
sin_family
=
AF_INET
;
destAddr
.
sin_family
=
localHost
->
h_addrtype
;
printf
(
"%s: waiting for data on port UDP %u
\n
"
,
argv
[
0
],
LOCAL_SERVER_PORT
);
flags
=
0
;
init_pcap
(
inet_ntoa
(
servAddr
.
sin_addr
));
struct
pcap_stat
pcapStatObj
;
/* server infinite loop */
while
(
1
)
{
memset
(
msg
,
0x0
,
MAX_MSG
);
/* receive message */
cliLen
=
sizeof
(
cliAddr
);
n
=
recvfrom
(
sd
,
msg
,
MAX_MSG
,
flags
,
(
struct
sockaddr
*
)
&
cliAddr
,
&
cliLen
);
pcap_dispatch
(
pcapDescriptor
,
1
,
pcapCallback
,
NULL
);
pcap_stats
(
pcapDescriptor
,
&
pcapStatObj
);
if
(
pcapStatObj
.
ps_drop
>
0
)
printf
(
"pcap: Packets received %d, dropped %d
\n
"
,
pcapStatObj
.
ps_recv
,
pcapStatObj
.
ps_drop
);
if
(
n
<
0
)
{
printf
(
"%s: cannot receive data
\n
"
,
argv
[
0
]);
continue
;
}
}
return
0
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment