Title: On receiving ancillary data
1On receiving ancillary data
- We use the recvmsg() function to obtain a
datagrams arrival-time as a UDP socket option
2The traceroute algorithm
- The idea is to send out a succession of packets
to an internet destination, with increasing
values for the IP headers Time-to-Live field,
knowing that whenever any packet arrives at a
router, its Time-to-Live field will get
decremented - Routers discard packets whose TTL is zero, and
return an ICMP error-message Time Exceeded to
the sender which shows that routers identity - Then this routing information can be displayed
3Algorithm implementation
- Probably the most natural way to think about
implementing this traceroute idea would be to
send ICMP Echo Requests - When the Time-to-Live field is sufficiently
large, the ICMP Echo Request will arrive at its
intended target, and an Echo Reply ICMP message
would get sent back, as with the well known
ping network utility
4Sending ICMP packets
Echo Request to D (TTL1)
10.0.1.1
10.0.1.2
10.0.3.1
10.0.3.2
10.0.2.1
10.0.2.2
Host A
Host B
Host C
Host D
Time Exceeded to A
Echo Request to D (TTL2)
10.0.1.1
10.0.1.2
10.0.3.1
10.0.3.2
10.0.2.1
10.0.2.2
Host A
Host B
Host C
Host D
Time Exceeded to A
Echo Request to D (TTL3)
10.0.1.1
10.0.1.2
10.0.3.1
10.0.3.2
10.0.2.1
10.0.2.2
Host A
Host B
Host C
Host D
Echo Reply to A
5Need a RAW socket
- For a Linux application to send an ICMP message,
it has to open a type of socket which normally
requires root privileges - You can look at our nicwatch utility for an
example that uses a RAW socket to access the
fields in a packets headers - Without root privileges we cant write a
traceroute utility that is based on ICMP
6The Linux workaround
- What we can do instead is to send UDP datagrams
which have increasing values for the TTL-field in
their IP-headers (since the TTL-field for any
outgoing packets is something that an
unprivileged application program can control with
a socket option) - We can detect the identity of routers that send
us Time Exceeded messages by looking at
ancillary data via recvmsg()
7Sending UDP packets
UDP message to D (TTL1)
10.0.1.1
10.0.1.2
10.0.3.1
10.0.3.2
10.0.2.1
10.0.2.2
Host A
Host B
Host C
Host D
Time Exceeded to A
UDP message to D (TTL2)
10.0.1.1
10.0.1.2
10.0.3.1
10.0.3.2
10.0.2.1
10.0.2.2
Host A
Host B
Host C
Host D
Time Exceeded to A
UDP message to D (TTL3)
10.0.1.1
10.0.1.2
10.0.3.1
10.0.3.2
10.0.2.1
10.0.2.2
Host A
Host B
Host C
Host D
Destinnation Unreachable to A
8Using an unlikely port?
- The most common way of getting back an
Destination Unreachable error-message (ICMP
Type 3) is by sending a datagram to a UDP port
which is not being used by any applications
currently running on the destination host (ICMP
Type 3, Code 3 Port is unreachable) but a
sender might not possess that knowledge for
certain, thus a best guess approach can be tried
9Other UDP senarios
- We might never get any response from a
destination host e.g., our datagram DID arrive
at its destination successfully, and thus
sendmsg() times out while waiting - Or our destination host lies behind some
firewall that has been erected along the path,
or a intermediate router could be configured to
block an ICMP response
10Your project 1
- Your first programming challenge is to try
implementing your own miniature version of the
traceroute utility, devising your own way of
handling the less common senarios - The main requirement will be to display the
IP-addresses for the various routers encountered
along a path to your target - Enhance that basic capability extra credit
11Message-header
struct msghdr void msg_name // optional
address socklen_t msg_namelen // size of
address struct iovec msg_iov // scatter/gather
array int msg_iovlen // no. of
members void msg_control // ancillary data
buffer int msg_controllen // ancillary buffer
length int flags // flags on received
message
struct iovec void iov_base size_t iov_len
12Ancillary control-data
The ancillary data that is returned by
sendmsg() in the buffer pointed to by its
message-headers cmsg_control field is
delivered in a succession of one or more
packages, each beginning with this struct
cmsghdr format, whose data may be followed by
padding to achieve a required alignment.
struct cmsghdr socklen_t cmsg_len //
data byte count, including header int cmsg_level
// originating protocols ID-number int cmsg_t
ype // protocol-specific type ID-number unsigned
char cmsg_data0 // variable amount of data
follows
To avoid the compiler generating code that would
be architecture-dependent, these packages of
ancillary data should be accessed using special
macros named CMSG_FIRSTHDR(), CMSG_DATA(),
CMSG_NXTHDR(), etc., and defined for Linux
systems in the header-file lt/usr/include/linux/soc
ket.hgt.
13Demo triptime.cpp
- We illustrate the role of socket options and
access to ancillary data with this example, which
sends a datagram to a host that is running our
msgserver echo-server, and uses a timestamp
that our socket binds to the returned datagram to
get the packets round-trip travel-time (in
microseconds)
message to server
./triptime stargate 54321
./msgserver
reply from server
stargate
round-trip travel-time
14The SO_TIMESTAMP option
- When this socket-layer option is enabled, and a
suitably sized buffer is provided for the
specified ancillary data, the network protocol
software reports the arrival-time of the datagram
messages it receives - Comparing arrival-time to departure-time allows
calculating a round-trip travel-time
15setsockopt()
- Here are the code-fragments used to open a
datagram socket, and then to enable its ability
to timestamp any arriving packets
int sock socket( AF_INET, SOCK_DGRAM,
IPPROTO_UDP ) if ( sock lt 0 ) perror(
socket ) exit(1) int oval 1 int olen
sizeof( oval ) if ( setsockopt( sock,
SOL_SOCKET, SO_TIMESTAMP, oval, olen ) lt 0 )
perror( setsockopt TIMESTAMP ) exit(1)
16struct timeval
- Linux systems support a data-structure that
allows time-of-day to be accurately recorded
(in seconds and microseconds)
seconds
micoseconds
struct timeval unsigned long tv_sec unsign
ed long tv_usec
This structure-type is defined in the header-file
lt/usr/include/sys/time.hgt
17gettimeofday()
- This library-function records the current
time-of-day in a struct timeval record - Our triptime.cpp example uses this to get the
departure-time of an outgoing packet
declare a struct timeval object struct
timeval now store the current time based on
the systems clock gettimeofday( now, NULL )
18The cbuf array
- The arrival-time for a received packet may be
obtained using the recvmsg() function with a
suitably initialized message-header - For the case of receiving timestamp data, the
struct cmsg buffer will need room for a struct
timeval object as its cmsg_data, in addition
to its struct cmsghdr header - We need to know sizes for C data-types
19Types for x86_64 Linux
- On our x86_64 Linux platform, the sizes for int
and long are 32-bits and 64-bits, respectively,
so well need buffer-space that can store 16
(844) bytes for the struct cmsghdr header,
plus 16 (88) bytes for the struct timeval
data-object - (Our demo actually allocates 40 bytes)
20Initializing mymsghdr
- Here are code-fragments that prepare our struct
msghdr for receiving the timestamp
unsigned char buf 40 0 , cbuf 40
0 struct iovec myiov1 buf, 40
struct msghdr mymsghdr mymsghdr.msg_name
paddr // server socket-address mymsghdr.msg_na
melen sizeof( paddr ) // socket-address
length mymsghdr.msg_iov myiov // address of
I/O-vector mymsghdr.msg_iovlen 1 // elements
in I/O-vector mymsghdr.msg_control cbuf //
address for control data mymsghdr.msg_controllen
sizeof( cbuf ) // control data buffer
size mymsghdr.msg_flags 0 // flag settings
(none) int rx recvmsg( sock, mymsghdr, 0
) // receive the datagram if ( rx lt 0 )
perror( recvmsg ) exit(1)
21Using the macros
- Here is how we use the systems macros to get the
timestamp on the arriving data
struct timeval tvrecv int tlen sizeof(
struct timeval ) struct msghdr msgp
mymsghdr struct cmsghdr cmsg for ( cmsg
CMSG_FIRSTHDR( msgp ) cmsg ! NULL cmsg
CMSG_NXTHDR( msgp, cmsg ) ) if ((
cmsg-gtcmsg_level SOL_SOCKET ) (
cmsg-gtcmsg_type SO_TIMESTAMP )) memcpy(
tvrecv, CMSG_DATA( cmsg ), tlen )
22Computing RTT
- The Round-Trip travel-time can be gotten by a
subtraction (arrival minus departure) provided we
convert each struct timeval record into a
single numerical value that expresses these times
in microseconds
convert structures to numbers (one-million
microseconds per second) unsigned long
long stamp0 tvsend.tv_sec 1000000LL
tvsend.tv_usec unsigned long long stamp1
tvrecv.tv_sec 1000000LL tvrecv.tv_usec
subtract departure-time from arrival-time to get
the round-trip travel-time unsigned long
long rtt stamp1 stamp0
23Observation
- Our msgserver.cpp echo-server program performs
a certain amount of processing between the time
it receives a datagram and the time it sends back
its response - It displays a report about the packets size
- It displays the text of the packets message
- It modifies a member of its I/O-vector array
- These steps take some time which gets included
in the clients round-trip measure
24In-class exercises
- Could you reduce the size of the cbuf40 array
in our triptime.cpp application, since it
appears the timestamp and its cmsghdr could fit
in fewer than 40 bytes of storage? - Could you shrink the round-trip travel-time by a
noticeable number of microseconds if you omitted
the servers system-calls that write information
to the screen-display?