Documente Academic
Documente Profesional
Documente Cultură
ADVANCEDSOCKETS
4.1
4.1.1Introduction
A gradualtransition of the Internet from IPv4 (Currentversion) to IPv6 (Next generation)
is probablyrequired. So it is importantthat existing IPv4 applicationscontinueto work with
newerIPv6 applications.
.
An IPv6 Telnet serversmust provide one that works with IPv4 serversand one
that work's with IPv6 servers.
One IPv6 Telnet client that can work with both IPv4 and IPv6 servers,.
One Telnet severthat can work with both IPv4 and IPv6 clients.
The hosts are running dualstacks,that is both and IPv4 protocol stack and an
IPv6 protocol stack.
There are four combinationsof clients and serversusing either IPv4 or IPv6 and we
show thesein Figure4.1
IPv4 server
Pv4client
Pv6client
Almostall existing
clientsandservers
Discussed
in section4.1.3
lPv6server
Discussed
i n s e c t i o n4 . 1 . 2
Simple modification to most
existineclientsand servers
Sourcecode portability
AdvoncedSockets
4.3
client
lPv4
client
l P v 6l i s t e n i n g
s o c k e tb o u n d e d
t o 0 : : 0 ,p o r t 8 8 8 8
lPv4-mapped
l P v 6a d d r e s s
zvo.oz.zzo.+z
Enet Pv4
ndr hdr
hdr
l P v Oa d d r e s s
5 f 1b : d f 0 0 : c e 3 e : e 2 0 0 :
2O:80O:2b37:6426
TCP
oata
Type Dport
0800 8888
E n e t lPv6 TCP T C P
n o r n o r h d r oala
J;ffi?ffi'
Fig 4.2 IPv6 server on dual -stack host serving IPv4 and IPv6 clients
An IPv4 client and an IPv6 client are on the left. The serveron the risht is written
using IPv6 and it is runningon a dual-stackhost.
The server has created an IPv6 listenrng TCP socket that is bound to the IPv6
wildcard addressand TCP port 8888.
Routerscould also connectthem, as long as all the routers supportIPv4 and IPv6.
Assume that both clients send SYN sesmentsto establisha connectionwith the
server.
IPV4 client
4.4
The TCP segmentfrom the IPv4 client appearson the wire as an Ethernetheader
followed by and IPv4 header,a TCP header,and the TCP data.
IPVS client
.
The TCP segmentfrom the IPv6 client appearson the wire as an Ethernet header
followed by and IPv6 anlPv6 header,TCP header,and the TCP data.
The Ethernet headercontains a type field of 0x86dd, which identifies the frame as
an IPV6 frame.
The TCP header in the IPV6 packet has the sameformat as the TCP headerin the
IPV4 packet,and containsthe destinationport of 8888'
the
IPv6
header
would
be
The receiving datalink looks at the Ethernet type field and passeseach frame to the
appropriate IP module.
Address conversion
.
The IPv4 module, probably in conjunctionwith the TCP module, detectsthat the
destination socket is an IPv6 socket,and the source IPV4 addressin the IPV4
headeris convertedinto the equivalentlPV4-mappedIPV6 address.
That mapped addressis returnedto the IPv6 socket as the client's IPv6 address
when acceptreturns to the serverwith the IPv4 client connection'
When accept returns to the server with the IPv6 client connection,the client's
IPv6 addressdoes not change from whatever source addressappearsin the IPv6
header.
The lpv6 serverstarts,createsan IPv6 listening socket,and it binds the wildcard address
to the socket.
2.
The IPv4 client calls gethostbynameand finds an A record for the server. The server
host will have both an A record and a AAAA record, since it supportsboth protocols
but the IPv4 client asks for only an A record.
3.
The client calls connectand the client's hosts sendan IPV4 SYN to the server.
4.
The serverhost receivesthe IPv4 SYN directedto the IPV6 listening socket,setaa flag
indicating that this connectionis using IPV4 -mapped IPV6 addressesand responds
with an IPV4 SYN/ACK. When the connection is established,the addressreturned to
the serverby acceptis the IPv4 mappedIPv6 address.
5.
AdvoncedSockefs
4.5
6.
Unless the server explicitly checkswhether this IPv6 addressis and IPv4 mapped IPv6
address(using the IN6_Is_l DDR_V4MAPPED macro), the server never knows that it
is communicating with an IPv4 client. The dual protocol stack handles this detail.
Similarly, the IPv4 client has no idea that it is communicating with an IPv6 server.
An underlying assumption in this scenario is that the dual - stack server host has both
an IPv4 addressand an IPv6 address.This will work until all the IPv4 addressesare taken.
The scenario is similar for an IPv6 UDP server,but the addressformat can change for
each datagram.For example, if the IPv6 server receives a datagram from an IPv4 client, the
addressreturned by recvfrom will be the client's IPv4 mapped IPv6 address. The server
respondsto this client's requestby calling sendtowith the IPv4 mappedIPv6 addressas the
destination.This addressformat tells the kernel to sendan IPV4 datagramto the client. But
the next datagram received for the server would be IPV6 datagram. But the next datagrams
receivedfor the servercould be an IP v6 datagrams,and recvfrom will return the IPv6 address.
It the server responds,the kernel will generatean IPv6 datagrar4.
Figure 4.3 summarizeshow a receivedIPv4 or IPv6 datagramis processed,depending
on the type of the receiving socket, for TCP and UDR assuming a dual stack host.
AF-INET
SOCK-DGRAM
sockaddr_in
lPv4sockets
revosocr<ets
{
AF_INET6
SOCK-STREAM
sockaddr_in6
AF'INET6
SOCK-DGRAM
sockaddrin6
address
returned by
acceptor
recvfrom
{,,*
lPv4 datagram
lPv6 datagram
Fig. 4.3 Processing ofreceived IPv4 or IPv6 datagrams, depending on type ofreceiving socket
4.6
Ifan IPv6 datagram is received for an IPv6 socket, nothing special is done
"IPv6" in the figure, one to TCP and one to
These are the two arrows labeled
UDP. IPv6 datagramsare exchangedbetween the client and server.
But when an IPv4 datagram is received for an IPv6 socket, the kernel returns
the corresponding IPv4 mapped IPv6 addressas the addressreturned by
accept(TCP) or recvfrom (UDP). These are the two dashed arrows in the
figure. This mapping is possiblebecausean IPv4 addresscan always be
representedas an IPv6 address.IPvA datagramsare exchangedbetween the
client and server.
The converseofthe previous bullet (an Ipv6 datagramis received for an Ipv4 socket)
is false: in general an IPv6 address connote be representedas an IPv4 address: therefore
there are no arrows from the IPv6 protocol box to the two IPv4 sockets.
Most dual- stackhostsshouldusethe following rules in dealing with listening sockets:
l.
2.
Ifa serverhas a listening IPv6 socketthat has bound the wildcard address,that socket
can accept incoming connections from either IPv4 clients or IPv6 clients. For a
connectionfrom an IPv4 client the server'slocal addressfor the connectionwill be the
corresponding IPv4 mapped IPv6 address.
3.
If a server has a listening IPv6 socket that has bound an IPv6 addressother than an
IPv4 mapped IPv6 address,that socket can accept incoming connectionsfrom IPv6
clients only.
An IPv4 server startson an lPv4-only host and createsan IPv4 listening socket.
2.
The IPv6 client starts,calls gethostbynameasking for only IPv6 addresses(It enables
the RES_USE_INET6 option). Since the IPv4-only server host has only A records, an
IPV4-mapped IPv6 addressis returned to the client.
3.
The IPv6 client calls connect with the lPv4-mappedIPv6 addressin the IPv6 socket
addressstructure. The kernel detects the mapped addressand automatically sendsan
IPv4 SYN to the server.
4.
AdvoncedSockels
4.7
AF-INET
SOCK-DGRAM
sockaddr_in
lPv4sockets
AF_INET6
SOCK-STREAM
sockaddr_in6
lPv6sockets
AF-INET6
SOCK-DGRAM
sockaddr_in6
address
returnedby
acceptor
recvfrom { , * .
lPv4datagram
lPv6datagram
Fig, 4.4 processing of client rcquests, depending on address type and socket type
In an IPv4 datagram arriving for an IPv6 server socket, the conversion ofthe received
addressto the IPv4-mappedIPv6 addressis done by the kernel and returned transparentlyto
the applicationby acceptor recvfrom.
In an IPv4 datagramneedingto be sent on an IPv6 socket the conversionofthe IPv4
addressto the IPv4- mappedIPv6 addressis done by the resolver and the mappedaddressis
then passedtransparentlyby the applicationto connector sendto.
4.8
NetworkProgramming
and Management
Summary of interoPerabilitY
of
Figure 4.5 summarizes this section and the previous section and the combinations
clients and servers.
IP6server
IPv4 server
IPv6 server
IPv4
-stackhost
dual
IPv6-onlyhost dual- stackhost
server
(A and AAAA) (A andAAAA)
IPv4-only (AAAA only)
host
(A only)
lPv4 client, IPv4- onlY host
IPv6 cl ent, IPv6 only host
IPv4 ci ent. dual-stackhost
IPv6 client. dual- stack host
IPv4
(no)
(no)
IPv4
IPv6
(no)
IPv4
(no)
IPv4
IPv6
(no*)
IPv4
IPv4
IPv6
IPv4
IPv6
Figure 4.5 Summary of interoperability between IPv4 and IPv6 clients and servers
IPv6_ADDRFORM socket option: change a socket type between IPv4 and IPv6,
by setsockopt function with IPv6-ADDRFORM option
There are small classesof IPv6 applications that must know whether they are talking
to an IPv4 peer. These applicationsneed to know if the peer's addressis an IPv4 mapped
IPv6 address.Twelve macros are defined to test an IPv6 addressfor certain properties.
Advonced Sockets
4.9
>
f,include< netinet/in.h
int lN6_|S_ADDR_UNSPECIFIED
(conststructin6_addr"aptr);
int lN6_|S_ADDR_LOOPBACK
(conststructin6_addr*aptr);
int lN6_IS_ADDR_MULTICAST
(conststructin6_addr*aptr);
int lN6_|S_ADDR_LINKLOCAL
(conststructin6_addr*apt|;
int lN6_lS_ADDR_SITELOCAL
(conststructin6_addr*aptr);
int lN6_IS_ADDR_V4MAPPED
(conststructin6_addr*aptr);
int lN6_lS_ADDR_V4COMPAT
(conststructin6_addr*aptr);
int lN6_|S_ADDR_MC_NODELOCAL
(conststructin6_addr*aptr);
int lN6_|S_ADDR_MC_LINKLOCAL
(conststructin6_addr*aptr);
int lN6_lS_ADDR_MC_SITELOCAL
(conststructin6_addr*aptr);
int lN6_|S_ADDR_MC_ORcLOCAL
(conststructin6_addr*aptr);
int lN6_lS_ADDR_MC_GLOBAL
(conststructin6_addr*aptr);
2.
NetworkProgramming
and Managemenl
listenfd,connfd;
clilen;
socklen_t
serv,cli;
struct sockaddr_in
:
fistenfd sockeI(AF_INET,SOCK_STREAM,0);
l*lPv4 structs*/
l*lPv4 socket*/
/*child*/
D u p 2 ( c o n n f d ,S T D E R R _ F I L E N O ) ;
close (connfd);
Exec(...);
)
l*Parenl*l
Close(connfd);
)
Fig.4.6 server that accepts inconting connection and execs new progranl
int
ali
socklen_t
clilen;
structsockaddr_in6
cli; /*lPv6struct*/
*ptr;
structhostent
af=AF_lNET6;
N_FlLENO,
Pv6,IPv6_ADD
RFORM,&af,
setsockopt(STDI
IPPROTO_I
sizeof(af));
clilen= sizeof(cli);
(0,&cli,&clilen)
Getpeername
;
ptr= gethostbyaddr(&cli.
sin6_addr,
16,AF_l
NET6);
Fig 4.7 converting an IPv4 socket to an IPv6 socket
From the fig 4.7 thg call to stockpot changesthe addressformat of the socket from
IPv4 to IPv6, and the call to getpeernamewillreturn an IPv4 mappedIPv6 address,assuming
the socketwas an IPv4 socket.But if this programis execedwith an IPv6 socketon standard
input, the call to setsockoptdoes nothing, as the addressformat is already IPv6.
AdvoncedSockels
4.1'l
Threaded servers
Expensive
.
2.
IPC (Inter-processcommunication)is requiredto passinformation betweenparent
and child after fork.
In order to avoid the above problems threadsare used. All threadswithin a process
share.
.
Processinstructions.
Most data,
Signalhandlersand signaldispositions,
4.12
elTno,
Priority
Lowercontext-switchingoverhead.
POSIX threadsstandard
l.
Pthreadslibrary
2.
3.
4.2.3 Disadvantages
.
Library functions that returnp ointers to internal static aruaysare not thread
2.
safe.
To make it thread-safe+ caller allocatesspacefor the result and passes
that pointer as argumentto the function
Advonced Sockels
13
4.13
Expensive
Private multiple-addressspaces
Belongsto a process
Cheap
Sharedsingle- addressspace
process
Threads
Kernel
Use
. Processesare largely
independent
Use
. Threads are part of same ttjob" and
are actively and closely cooperating
4.14
and Management
NetworkProgramming
Process
gigabyta
virtual
address
Softwareengineeringperspective
-Applications are easierto structureas a collection of threads
Critical sections
- Synchronizationprimitives: blocking, spin-lock (busy-wait)
- Condition variables
Kernel versususer-levelthreads
AdvqncedSockets
4.15
In user space
In kernel space
User-levelThreads
.
Examples
- POSIX Pthreads
- Mach c-threads
- Solaris threads
ill
I l
fEl
Thread
run-time
system
Thread
table
Kernel
I PCBl+l PCBH...
Fig .4.9 User level thread
4.16
and Managemenl
NetworkProgramming
Thread
table
Fig.4.I0 Kernel Thread
AdvoncedSockets
4.' t7
4.2.10Singleand MultithreadedProcesses
registers
*l
thread
(
multithreaded
single-threaded
4.2.12
Per Processitems
.
.
.
.
.
.
.
Addressspace
Globalvariables
Openfiles
Child processes
Pendingalarms
Signalandsignalhandlers
Accountinginformation
Inpufoutput
N threads
Server
Fig. 4. I2 Client and server with threads
4.18
NetworkProgramming
and Management
4.2.13
r
Ii
\r/o/"\r,.rot,
./\J \1
/l;i.;i;
per-connection
threads
.--;
o+
t-/
-bremore
Wl;j.;i;
,_,JI
per-obiect
threads
o. _u.r''.r0,,
\vqr'-
r'+L/+Lr ro-oj.'t,
/ \u,
a.Thread-per-request
b.Thread-per-connectionc.Thread-per-object
Fig.4.13 Threaded Server A)"hitr"turx
The thread-per-requestarchitecture
o
d coordinatorthreadreadsincoming requests
exits
The thread-per-connectionarchitecture
.
Sequentialprocessingofrequests
Finite statemachine
AdvoncedSockets
4.19
event-drivenprgromming model
Interrupt-driven model
.
Processesinsteadofthreads
Explanation
Sequential processing of requests
Getsrequest,processesit. getsnext
CPU idle while datais retrievedfrom disk
Poor performance
Finite state machine (Interrupt/event -driven prg. model)
Use non-blockingsystemcalls (read)
-
Processesinstead of threads
-
(e.g.,manyCGI (CommonGatewayInterface)
Use of IPC facilitiesfor communicatron
and Web serverrmplementations)
(heavyweight solution)
4.20
NetworkProgramming
and Management
e.printStackTrace0;
)
)
)
classecho{
Socketsock;
echo(Socket
sock)throwslOException
{
in = new BufferedReader(
BufferedReader
getlnputStream0))
newInputStreamReader(sock.
;
ll lrom socket
out : new BufferedWriter(
BufferedWriter
getOutputStream
newOutputStreamWriter(sock.
0));
// to socket
Strings;
!: null){
while((s = in.readLine$)
out.write(s);
out.newLine0;
out.flush0;
if (s.equals("exit"))
break;
)
sock.close0;
)
)
. this is single-threaded - only servicesone client at a time
4.2.15
Multithreaded Server
Introduction to Multithreading
.
A thread is an independentstreamofexecution
Different threads in the same processshare a global environment (e.g. same object
instance)
Application-levelparallelism
Parallelismon multiprocessormachines
Advonced Sockefs
4.21
Multi-threading Issues
'
Safety - how to synchronize threads so that they do not interfere with one another
'
Liveness-how to avoid deadlocksituationsto ensurethat all threadsmake progress
'
Disoatcher
thread
Server
Workerthread
Requestcomingin
fromthe network
Webserverprocess
User
space
r0.t
Web servercac
Kernel
space
Kernel
Networkconnection
Disk
4.22
NetworkProgramming
and Management
Characteristics
Model
Threads
blockingsystemcalls
Parallelism,
process
Single-threaded
blockingsystemcalls
No parallelism,
machine
Finite-state
nonblockingsystemcalls
Parallelism,
Multi-threadedserver
publicclassmultiserver
{
staticStringport = "5194";
publicstaticvoidmain(String[]
argv)
{
== 0)
if (argv.length
multiserver(port);
else
multiserver(argvIO])
;
)
port)
publicstaticvoidmultiserver(String
lltcplipversion
trv{
parselnt(port)) ;
nteger.
srv = new ServerSocket(l
ServerSocket
while(true)
Multithreaded Client
2.
Advonced Sockets
4.23
3.
4.
lnteract with human user and remote server in parallel (non blocking towards
user)
Local dataprocessing
Compounddocuments:Drag-and-drop;inplace editing(notifications)
thread_exit(...):terminatesthe callingthread
'
4.3
4.24
Example
void * func (void*); //functionprototype
pthread_ttid; //to holdthreadlD
(&tid,NULL,func,NULL);
Pthread_create
*
void func (void* arg)
t
)
Pthread_join Function
#include<pthread.h>
Int pthreadjoln (pthread-ttld, vold *t status);
//Returns0 lf OK, posltlveExxxvalue on error
.
.
4.3.1.3
pthread_selfFunction
.
4.3.1.4
#lnclude<pthread.h>
(pthread_ttld);
Int pthread_detach
//Returns0 lf OK, poslllveExxxvalue on error
*
When a joinable thread terminates thread ID and exit status are retained until another
thread calls pthreadjoin.
Advonced Sockets
4.25
The pthread_detach
functionchangesthe specifiedthreadso that it is detached.
Example:pthread_detach(pthread_self0);
4.3.1.5
pthread_exitfunction
Clent
pthread_create
Fromthefig.4.l6:
4.26
NetworkProgramming
and Management
unpthread.hheader
It includesour normal unp.hheader,followed by the <pthread.h> header,and then
definesthe function prototypesfor our wrapperversionsof thepthread-XXX functionswhich
all beginwith pthread_.
Saveargumentsin externals
Storethe valuesof the two argumentsto str_cli: fp,(thestandardVO FILE pointerfor
theinput file), andsockfd,(theTCP socketthat is connectedto the server)in externalvariables.
Createnew thread
.
The threadis createdandthenew threadID is savedin tid.
.
#include "unpthread.h"
void *copyto(void*);
sockfd;
staticint
/* globalfor both threadsto access*/
*fp;
staticFILE
void
*fp_arg,int sockfd_arg)
str_cli(FILE
{
recvline[MAXLINE];
char
pthread_t tid;
sockfd = sockfd_arg;
/* copy argumentsto externals*/
fp = fp_arg;
NULL,copyto,NULL);
Pthread_create(&tid,
> 0)
recvline,MAXLINE)
while(Readline(sockfd,
stdout);
Fputs(recvline,
)
void *
*arg)
copyto(void
{
char sendlinelMAXLlNEl;
MAXLINE,
fp) != NULL)
while(Fgets(sendline,
sendline,strlen(sendline));
Writen(sockfd,
SHUT-WR); /* EOFon stdin,sendFIN*/
Shutdown(sockfd,
return(NULL);
whenend-of-file
on stdin*/
/* 4return(i.e.,threadterminates)
)
Fig 4.17 str_clifunctionusingthreads
From the frg.4.l7:
Main thread loop: copy socket to standard output
The main thread calls readline andfputs, gopying from the socket to the standardou$ut.
Terminate
Advonced Sockefs
4.27
by usingour tcp_listenfunction.
It is madeas protocolindependent
"unpthread.h
#include
staticvoid 'doit(void*);
int
main(intargc,char**argv)
/* eachthreadexecutesthisfunction*/
t
int
listenfd,connfd;
socklen_t
addrlen,len;
structsockaddr rcliaddr;
if (argc== 2)
listenfd= Tcp_listen(NULL,
argv[1],&addrlen);
=
=
(argc
else if
3)
listenfd= Tcp_listen(argv[1
], argv[2],&addrlcn[
else
tcpserv0lt I ");
err_quit("usage:
cliaddr= Malloc(addrlen);
for(;;){
len = addrlen;
connfd = Accept(listenfd,
cliaddr,&len);
Pthread_create(NULL,
NULL,&doit,(voidr) connfd);
)
)
staticvoid *
doit(voidrarg)
{
(pthread_self
Pthread_detach
0);
str-echo((int)arg);/* samefunctionas before'/
Close((int)arg); /* we are done with connectedsocket*/
return(NULL);
)
Fig.l.It TCPEchoserverasing Thretds
Fromthe fig.4.18:
4.28
and Management
NetworkProgramming
Create a thread
.
is calledinsteadof fork.
When acceptreturns,pthread-create
Thread functlon
.
'
With fork, the child did not needto closethe connectedsocketbecausethe child
then terminatedand all opendescriptorsareclosedon processtermination.
to work on
The integervariableconnfdis a void pointer,but this is not guaranteed
all systems.To handlethis correctlyrequiresadditionalwork.
First notice that we cannotjust passthe addressof connfdto the new thread.That is,
the following doesnot work
int
main( int argc,** argv)
int listenfd,connfd;
for (;;){
len= addrlen;
connfd = Acept ( listenfd,cliaddr,&len);
Advonced Sockcfs
4.29
pthread_create
(&tid,
NULL,&doit,
&confd)
;
staticvoid*
doit(void"arg){
int connfd:
connfd=*((int*)arg);
pthread_detach
(pthread_self
0);
str_echo((int)arg); /* samefunctionsas before*/
close((int)
arg); /* we aredonewithconnected
socket*/
return(NULL);
)
From an ANSI C perspectivethis is OK that we can castthe integerpointer to be a void
x and then cast this poiner back to an integerpointer.
The problem in this program is that it is not clear, what this pointer actually points
to.
Thereis one integervariableconnfd in the main threadand eachcall to acceptoverwrites
this variablewith a new value ( the connecteddescriptor).The following scenariocan occur,
l.
2.
3.
Another connectionis ready and the main thread runs again ( before the newly
created thread). accept returns, connfd ils stored , and the main thread calls
pthread_create.
'
Even though two threadsare created,both will operateon the final value storedinto
connfd. The problem is that multiples threadsare accessinga sharedvariable ( the
integer value in connfd) with no synchronization.
'
'
This is fine given the way that C passesinteger valuesto a called function ( a copy of
the value is pushedonto the stack for the called function).
int
l i s t e n f d ,* i p t r ;
socklen_t
a d d r l e n ,l e n ;
s t r u c ts o c k a d d r* c l i a d d r :
if (argc== 2)
l i s t e n f d= T c p _ l i s t e n ( N U L La ,r g v [ 1 ] ,& a d d r l e n ) ;
4.30
NetworkProgramming
and Management
elseif (argc= = 3)
listenfd= Tcp_listen(argv[1
], argv[2],&addrlen);
else
err_quit("usage:
tcpservOl[ <host> ] <serviceor port>");
cliaddr= Malldc(addrlen);
for(;;){
len = addrlen:
iptr = Malloc(sizeof(int));
*iptr = Accept(listenfd,
cliaddr,&len);
Pthread_create(NULL,
NULL,&doit,iptO;
l
I
staticvoid *
doit(void*arg)
{
int connfd;
connfd- *((int*) arg);
free(arg);
(pthread_self
Pthread_detach
0) ;
str_echo(connfd); /* samefunctionas before*/
Close(connfd);
/* we are donewithconnectedsocket*/
return(NULL);
)
Fig.4.l9 TCP Echo server using threads with more portable argument passing.
Each time we call accept we first call malloc and allocate space for an integer
variable, the connecteddescriptor.
This gives each thread its own copy of the connected descriptor.
The thread fetches the value of the connected descriptor and then calls free to
release the memory.
That is, calling either function from a signal handler while the main thread is in
the middle of one of thesetwo functionshasbeena recipe for disasters,becauseof
static data structures that are manipulated by these two functions.
So it requires these two functions, along with many others, to be thread- safe.
This is normally done by some form of synchronization performed within the library
functions that is transparent to us.4.4.2Thread-safeFunctions
.
If a function usesany static variables(or global memory) it's not safe to use
with threads!
Advonced Sockets
4.31
It must satisfy the need for multiple threadsto accessthe sameshareddata, and
the need for a sharedpiece of data to be accessedby only one thread at any
given time.
re-entrancy: Basically, writing code in such a way that it can be interrupted during
one task, reenteredto perform anothertask, and then resumedon its original task.
This usually precludesthe saving of state information, such as by using static or
global variables.
thread-local storage: Variables arelocalized so that eachthread has its own private
copy.The variablesretaintheir valuesacrosssubroutineand other codeboundaries,
and the code which accessesthem might not be reentrant,but since they are local
to each thread,they are thread-safe.
make changesto a private copy of the shareddata and then atomically updatethe
shareddata from the private copy. Thus, most of the code is concurrent,and little
time is spent serialized.
4.32
3.
*,pr{{
Key[1]
Flag
ptr
Destructor
Flag
ptr
Destructor
Flag
K e y [ 1 2 7 ] Destructor
ptr
Fig.4,2l possible implementation of thread-specific data
Advonced Sockofs
4.33
'
The flag in the key structure indicates whether this array element in currently in
use, and all the flages are initialized to be "not in use".
'
'
Its index, 0 through 127, is called the key and this index is returnedto the calling
thread.
The "destructor pointer, " is the other memberof the key structure.
Thread n
Pthread{}
Otherthread
information
Pkey[0]
Pointer
NULL
Pkey[1
]
Pointer
NULL
Pkeyll27)
Pointer
NULL
Pkey[0]
pkey[1]
Thread
specific
data
ilems
pkeyll2zl
'
These 128 pointersare the "values" associatedwith eachof the possible 128 "Key
"
in the process.
'
Each thread can then store a value (pointer) for the key, and each thread normally
obtainsthe pointer by calling malloc.
An example of how thread-specificdata is used, assumingthat our readline function
usesthread-specificdata to maintain per-threadstateacrosssuccessivecalls to the function.
Our readline function is modified to follow thesesteps.
4.34
2.
One of the threads will be the first to call readlilne and it in turn calls
pthread-key-create. The system finds the first unused key structure inFig.4.2l
NetworkProgramming
and Management
readline calls pthread_getspecificto get the pkey(1) value for this thread,and the
returnd value is a null pointer . Therefore readline calls malloc to allocate the
memory that it needsto keep the per-threadinformation acrosssuccessivecalls to
readline for this thread. readline initializes this memory as needed and calls
pthread_setspecific
to set the thread-specificdatapointer (pkey[1]) for this key to
point to the memory that it.just allocated. The calling thread ThreadOin the
processfrom the fi9.4.23.
Thread0
Threadn
Thread
specific
data
items
Pkey[1
27]
datastructures
System
In this figure the pthread structure is maintained by the system , but the actual threaddoes
specificdatathat we malloc is maintainedby our function . All that pthread-setspecific
is set the pointer for this key in the pthread structure to point to our allocated memory.
Similarly, all that pthread_getspecificdoes is return that pointer to us.
4.
Another thread, say thread n, calls readlilne, perhaps while thread 0 is still
exeecutingwithin readline.
readline calls pthread*onceto initialize the key for this thread-specificdata item,
but since it has alreadybeen called, it is not called again.
5.
readlinecalls pthread-getspecificto fetch the pkey [1] pointer for this thread,and
a null pointer is returned. This thread then calls malloc follwed by pthreadsetspecific,just like thread0,initializing its thread-specificdata for this key(l). It
is shown infie.4.24.
Advonced Sockels
4.35
Thread
0
Pkey[0]
Threadn
NULL
Pkey[1
]
Pkey[1
27]
Pkey[0]
Pkey[1]
Pkeyll27l
Svstem
datastructures
Memoryallocaled
by thread
6.
Thread n continues executing in readline, using and modifying its own threadspecific data.
pthread_once0
is normally calledevery time a function that usesthread-specificdata
iscalled,it usesthe value in the variable pointed to by onceptr to guaranteethat
init0functionis calledonly one time per process.
4.36
NetworkProgramming
and Management
pthread_key_create)must be called only one time for a given key within a process.The
destructorfunction will be called at the terminationof the thread'
Typical usageof thesetwo functions (ignoring error returns) is as follows:
pthread-key-trl-key;
pthread_once_t
rl_once= PTHREAD-ONCE-lNlT;
void
*
readline_destructor(void
Ptr)
t
free (pt0;
)
void
readline_once(void)
t
(&r1_key,readline-destructor)
pthread_key_create
;
)
ssize_t
r e a d l i n(e. . ,)
t
:
pthread_once(&r1
_once,readline_once)
== NULL){
il (( ptr= pthread_getspecific(rl_key))
p t r = M a l l o c( . . . ) ;
(rl-key,ptr);/*intialilze
memorypointedto by ptr */
pthread_setspecific
)
... /*usethe valuespoinmtedto by ptr*/
I
'
.
This function uses the value pointed to by its onceptr argument (the contents of
the variable rl_once) to make certain that its init function is called only one time.
Advonced Sockefs
4.37
#include <pthread.h>
void *pthread_getspecific(pthread_key_t
key);
void *pthread_setspecific(pthread_key_t
key,constvoid *value);
returns : 0 if OK, positive Exxx value on error
'
These two functions are used to fetch and store the value associatedwith a key.
'
'
4.5
The argument to pthread-key- create is a pointer to the key while the arguments
to the get ants set functions are the key itself
Mutexes
Mechanismfor thread coordinationand svnchronization
l.
Semaphores
2.
mutex calls
Semaphores
o
'
Mutex
'
r
4.38
due to raceconditions.
Mutexesare usedto preventdatainconsistencies
Advonced Sockefs
4.39
Without Mutex
With Mutex
/* Note scope of variableand mutex are the same */
pthread_mutex_t
mutexI =
PTHREAD_MUTEX_INITIALIZER;
int counter=0;
int counter=0;
/* FunctionC */
voidfunctionC0
/* FunctionC */
void functionC0
{
pthread_mutex_lock
( &mutexl
counter++
pthread_mutex_unlock(
&mutexl) ;
counter++
)
Possibleexscutionsequence
Thread I
Thread 2
Thread I
counter=0
counter= 0
counter= 0
counter= 0
counter=
I
counter: I
counter = I
Thread2 lockedout.
Thread 2
ThreadI hasexclusiveuseof
woriqhla
anrrniFr
counter= 2
When a thread terminates the main loop decrementsboth nconn and nlefttoread.
void*
(void*vptr)
do_get_read
{
int
fd, n;
char
linelMAXL|NEl;
*fptr;
structtile
*)
fptr = (structfile vptr;
fd = Tcp_connect(fptr->f_host,
SERV);
=
fptr->f_fd fd;
printf("do_get_read
for %s,tdY"d,thread%d\n",
fptr->f_name,
fd, fptr->f_tid);
write_get_cmd(fpt4;
/* write0the GETcommand*/
l* 4Readserver'sreply *l
for(;;){
== g;
if ((n = Read(fd,
line,MAXLINE))
break;
/* serverclosedconnection*/
printf("read
%d byteslrom %s\n",n, fptr->f_name);
4.40
NetworkProgramming
and Management
)
", f ptr-> f-n ame)
printf("end-of-f
ile on o/os\n
;
Close(fd);
*/
/* clearsF-READING
fptr->f-flags= F-DoNE;
*/
return(fpt0;
/* terminatethread
l
/* end do_get_read*/
Fig. 4. 2 5 do-g et-rea d fu n ctio n
Fromthe fig.4.25,
Thesetwo decrementsare placedin the do_get-readfunction in which eachthread
It resultsin a slight
beforethethreadterminates.
thesetwo countersimmediately
decrement
concurrentprogrammlngerror.
The problemin the functionthat eachthreadexecutesis that thesetwo variablesare
a variable,that
If one threadis in the middleof decrementing
global,not thread-specific.
the samevariable,an error
and anotherthreadexecutesanddecrements
threadis suspended,
canresult.
For example,Assume that the C compiler turns the decrementoperatorinto 3
instructions:
.
Decrementthe register.
scenarios
Possible
ThreadA is runningandit loadsthevalueof nconninto a register.
l.
2.
3.
Advonced Sockels
4'41
We get worse the potential for a problemby fetching the current value of counter,
printing the new value,and then storingthe new value.
4.42
NetworkProgramming
and Managoment
Usage
Mutex variablesmust be declaredwith type pthread-mutex-t,and must be
initialized before they can be used.There are two ways to initialize a mutex
variable:
l.
2.
4.43
#include
"unpthread.h"
#define
NLOOP5000
by the threads*/
/* this is incremented
= PTHREAD_MUTEX_lNlTlALlZER;
pthread_mutex_tcounter_mutex
*doit(void
*);
void
int
counter;
int
main(intargc,char**argv)
pthread_t tidA,tidB;
Pthread_create(&tidA,
NULL,&doit,NULL);
Pthread_create(&tidB,
NULL,&doit,NULL);
4wail
for
both
threadsto terminate*/
l*
Pthreadjoin(tidA,
NULL);
Pthreadjoin(tidB,
NULL);
exit(0);
)
void *
doit(void*vptr)
{
int
i, val;
l*
* Eachthreadfetches,prints,and increments
the counterNLOOPtimes.
*rThevalueof the countershouldincreasemonotonically.
for (i = 0; i < NLOOP;i++) {
(&counter_mutex)
Pthread_mutex_lock
;
val = counter;
printf("o/od:
%d\n",pthread_selffl,
val + 1);
counter= vrl* li
Pthread_mutex_unlock(&counter_mutex)
;
)
return(NULL);
)
Fi9.4.27.Correctedversionof fig.4.26usinga mutexto protectthe sharedvariable
.
Declare a mutex named counter_mutex and this mutex must be locked by the
thread before the thread manipulates the counter variable.
When we run this program, the output is always correct: the value is incremented
monotonically and the final value printed is always 10000.
4.6
Conditionvariables
4.6.1 Introduction
.
Condition variables provide yet another way for threads to synchronize. While
mutexesimplement synchronizationby controlling thread accessto data, condition
variablesallow threadsto synchronizebasedupon the actual value ofdata.
4.44
NetworkProgrammingand Management
Main Thread
.
mutex
Declareand initialize an associated
Thread B
. Do work
. Lock associatedmutex
. Changethe value of the global
variablethat Thread-A is waiting upon.
. Check value of the global ThreadAwait variable.If it fulfills the desired
condition,signalThread-A.
. Unlock mutex
. Continue
Advonced Sockefs
15
4.45
ndone:
/* numberof terminated
threads*/
pthread_mutex_t
= PTHREAD_MUTEX_INTIALIZER;
ndone_mutex
We thenrequirethat eachthreadincrementthis counterwhen it terminates,beingcareful
to usethe associated
mutex.
4.6.2 Functions used in conjunction with the condition variable:
o
Creating/Destroying:
*
pthread_cond_init
pthread_cond_t
cond:
PTHREAD_COND_INITIALIZER;
pthread_cond_destroy
Waiting on condition:
*
pthread_cond_wart
4.6.2.1
Wakingthreadbasedon condition:
*
pthread_cond_signal
Purpose
Inittalizes a condition variable and setsits attributes.
Syntax
#include <pthread.h>
int pthread_cond_init(pthread_cond_t*condition, pthread_condattr_t*attr);
Both return: 0 if OK, positive Exxx value on error
4.46
NetworkProgramming
and Management
Description
The pthread_cond_initsubroutineinitializes a new condition variable,and setsits
attributesaccordingthe conditionattributesobjectattr.
After initializationof the conditionvariable,the conditionattributesobjectcan be
deleted.
reusedfor anotherconditionvariableinitialization.or
Parameters
condition Specifiesthe conditionto be created.
attr Specifiesthe conditionattributesobjectto usefor initializingthe conditionvariable.
If the valueis NULL. the defaultattributes
valuesareused.
pthread_cond_destroy
4.6.2.2
, PurposeDeletesa conditionvariable.
Syntax
#include<pthread.h>
*condition);
(pthread_cond_t
int pthread_cond_destroy
Bothreturn:0 if OK, positiveExxxvalueon error
Description
The pthread_cond_destroy
subroutinedeletesthe condition variable.After deletionof
the condition variable, the condition parameteris not valid until it is initialized again by a
call to the pthread_cond_init subroutine.
Parameter
Condition -Specifiesthe condition variable to delete.
4.6.2.3
Advonced Sockets
4.47
Description
The pthread_cond_waitand pthread_cond_timedwait
functions are used to block on a
condition variable. They are called with mutex locked by the calling thread or undefined
behaviourwill result.
These functions atomically releasemutex and causethe calling thread to block on the
conditionvariablecond; atomicallyheremeans" atomicallywith respectto accessby another
thread to the mutex and then the condition variable". That is, if another thread is able to
acquire the mutex after the about-to-blockthread has releasedit, then a subsequentcall to
pthread_cond_signalor pthread_cond_broadcast
in that thread behavesas if it were issued
after the about-to-blockthread has blocked.
Upon successfulreturn, the mutex has been locked and is owned by the calling thread.
When using condition variablesthere is always a boolean predrcateinvolving shared
variablesassociatedwith eachconditionwait that is true if the threadshouldproceed.Spurious
wakeupsfrom the pthread_cond_waitor pthread_cond_timedwait
functionsmay occur.Since
the return from pthread_cond_waitor pthread_cond_timedwaitdoesnot imply anything about
the value of this predicate,the predicateshould be re-evaluatedupon such return.
The effect of using more than one mutex for concurrent pthread-cond-wait or
thread_cond_timedwaitoperationson the same condition variable is undefined; that is, a
condition variable becomesbound to a unique mutex when a thread waits on the condition
variable,and this (dynamic) binding ends when the wait returns.
A thread that has been unblockedbecauseit has been canceledwhile blocked in a
call to pthread_cond_waitor pthread_cond_timedwait
doesnot consumeany conditionsignal
that may be directedconcurrentlyat the condition variable if there are other threadsblocked
on the conditronvariable.
The pthread_cond_timedwaitfunction is the sameas pthread_cond_waitexcept that
an error is returned if the absolute
time specifiedby abstimepasses(that is, systemtime
equalsor exceedsabstime) before the condition cond is signaled or broadcasted,or if the
absolutetime specifiedby abstimehasalreadybeenpassedat the time of the call. When such
time-outs occur, thread_cond_timedwaitwill nonethelessreleaseand reacquirethe mutex
referencedby mutex. The functron pthread_cond_timedwaitis also a cancellationpoint.
If a signal is delivered to a thread waiting for a condition variable, upon return from
the signal handler the thread resumeswaiting for the condition variable as if it was not
interrupted,or it returns zero due to spuriouswakeup.
Parameters
Condition - Specifiesthe condition variable to wait on. mutex - Specifiesthe mutex
used to protect the condition variable. The mutex must be locked when the subroutineis
called. timeout - Points to the absolutetime structurespecifying the blocked statetimeout.
4.48
NetworkProgramming
and Management
Subroutine
or pthread_cond_broadcast
4.6.2.4 pthread_cond_signal
Purpose-Unblocksone or morethreadsblockedon a condition.
Syntax
# i n c l u d e< p t h r e a d . h >
i n t p t h r e a d _ c o n d _ s i g n a( pl t h r e a d - c o n d - t* c o n d i t i o n ) ;
int pthread_cond_broadcast(pthread-cond-t *condition);
Both return: 0 if OK positive Exxxvalue on error
Description
Thesesubroutinesunblock one or more threadsblocked on the condition specifiedby
condition. The pthread_cond_signalsubroutineunblocks at least one blocked thread,while
subroutineunblocks all the blocked threads.
the pthread_cond_broadcast
If more than one thread is blocked on a condition variable, the scheduling policy
determinesthe order in which threadsare unblocked.When eachthreadunblockedas a result
o f a p t h r e a d _ c o n d _ s i g n a lo r p t h r e a d _ c o n d _ b r o a d c a srte t u r n s f r o m i t s c a l l t o
pthread_cond_waitor pthread_cond_timedwait,the thread owns the mutex with which it
called pthread_cond_waitor pthread_cond_timedwait.The thread(s) that are unblocked
contendfor the mutex according to the schedulingpolicy (if applicable),and as if eachhad
called pthread_mutex_lock.
functions may be called by a thread
The pthread_cond_signalor pthread_cond_broadcast
whether or not it currently owns the mutex that threads calling pthread-cond-wait or
pthread_cond_timedwaithave associatedwith the condition variable during their waits;
however, if predictable schedulingbehavior is required, then that mutex is locked by the
threadcalling pthread_cond-signalor
pthread_cond_broadcast.
If no thread is blocked on the condition, the subroutinesucceeds,but the signalingof
the condition is not held. The next thread calling pthread_cond-waitwill be blocked.
Parameter
condition - Specifiesthe condition to signal.
4.7
Row sockets
4.7.1 Introduction
. It provides accessto internal network protocols and interfaces.
.
It provides accessto ICMP.
.
R a w s o c k e t s a l l o w a n a p p l i c a t i o n t o h a v e d i r e c t a c c e s st o l o w e r - l e v e l
communicationprotocols.
Advonced Sockels
4.49
Raw sockets are intended for advanceduserswho want to take advantageof some
protocol featurethat is not directly accessiblethrough a normal interface,or who
wants to build new protocols on top of existing low-level protocols.
'
Raw socketsprovide three featuresnot provided by normal TCP and UDP sockets;
l.
Raw socketsare used to read and write ICMPv4 IGMPv4 and ICMPv6 packets.The
ping program, for examplesendsICMP echo requestsand receivesICMP echoreplies.
The multicast routing daemon,mrouted , sendsand receivesIGMPv4 packets.
This capability also allows ICMP or IGMP applicationsto be handledentirely as user
processes,insteadof putting more code into the kernel. The router discovery daemon
processestwo ICMP messages(rounderadvertisementand router solicitation) that the
kernel knows nothing about.
2.
With a raw socket a processcan read and write IPv4 datagramswith an IPv4 protocol
field that is not processedby the kernel.Most kernelsonly processdatagramscontaining
valuesof I (ICMP), 2 (IGMP),6 (UDP). The OSPFrouting protocol doesnot use TCP
or UDP but uses IP directly, setting the protocol field of the IP datagramsto 89. The
gatedprogram that implementsOSPF must use a raw socketto read and write theseIP
datagrams.This capability will carry over tolPv6 also.
3.
With a raw socket a processcan build its own IPv4 header,using the IP_HDRINCL
socketoption.
3 4
7 8
1 5 1 6
versi0nheader
qontino
lcnnlh
type of
identifccation
timeto live
31
Totallength
Offset
0lPlyl Fragment
HeaderChecksum
Protocol
32-bitsourcelPv4adress
20 bytes
32-bitdestination
lPv4adress
options(ifany)
data
4.50
NetworkProgramming
and Management
Protocolfield: I
ICMP
IGMP
TCP
I7
UDP
l.
R/W ICMPv4.IGMPv4.ICMPv6
ex. Ping
2.
by kernel
not processed
R/W otherdatagrams
ex. Gated= implementOSPF(protocol: 89)
3.
4.8
Raw socketcreation
The stepsinvolvedin creatinga raw socketareas follows'
l.
Advonced Sockeis
4.51
SourceAddress
PacketId
Total Lensth
3.
Bind can be called on the raw socket,but this is rare. This function setsonly the local
address;there is no conceptof a port numberwith a raw socket.With regardto output,
calling bind setsthe sourceIP addressthat will be used for datagramssent on the raw
socket(but only if the I_HDRINCL socketoption is not set). If bind is not called, the
kernel setshe sourceIP addressto the primary IP addressof the outgoing interface.A
raw socketcan be bound to a specificlocal addressusrngthe bind 0 call. If it isn't
bound all packetswith the specifiedIP protocol are received.In addition a RAW socket
can be bound to a specificnetworkdeviceusing SO_BINDTODEVICE.
4.
Connect can be called on the raw socket,but this is rare. This function sets only the
foreign address:again, there is no conceptof a port number with a raw socket.With
regardto output,calling connectlets us callwrite or sendinsteadof sendto, sincethe
destinationIP addressis already specified.
4.9
If the IP_HDRINCL option is not set, the starting addressof the data for the
kernel to write specifiesthe first byte following the IP header,because
the kernal
will built the IP headerand prependit to the data from the process.Thekernel sets
the protocol field of the Ipv4 headerthat it builds to the third argumentfrom the
call to the socket.
4.52
NetworkProgramming
and Management
3.
If the IP_HDRINCL option is set,the startingaddressof the data for the kernel to
write specifies the first byte of the IP header. The amount of data to wite must
include the size of the caller's IP header.The processbuilds the entire IP header,
except (a)the Ipv4 identification field can be set to zero, which tells the kernal to
set this value, and (b) the kernel always calculatesand stores the lpv4 header
checksum.
4.
Raw SocketOutput
RawSockets
lPv4= ByApplication
lPv6+ By Kernel
Kernel
1.
IP
Sendto/ sendmsg+ destination
connect+ write / writev / send
2.
3.
4.
Fragmentationby kernel
With IPv4 it is the responsibilityof the userprocessto calculateand set any header
For example.In Pingprogramwe
containedin whateverfollowstheIPv4header.
checksums
mustcalculatetheICMPv4checksumandstoreit in theICMPv4headerbeforecallingsendto.
4.9.2 UsingIPv6 Raw Sockets
Raw socketsare usedin both IPv4 and IPv6 to bypassthe TCP and UDP transport
layers.
Advonced Sockets
4.53
lPv4
lPv6
Use
A c c e s sI C M P v 4 , I G M P v 4 ,
and to read and write IPv4
datagramsthat contain a protocol
field the kernel does not
recognize.
Byte
order
Not specified.
Send
and
receive
complete
packets
Yes
All fields in the protocol headerssent or received on a raw IPV6 socket are in
network byte order.
'
nt offset =2;
(offset))< 0)
if( setsockopt(sockfd,IPPROTO_lPv6,IPv6_CHECKSUM,&offset,sizeof
error
This not only enables checksumson this socket, it also tells the kernel the byte offset
of the l6-bit checksum: 2 bytes from the start of the application data in this example. To
disablethe option it must be set to -1. When enabledthe kernel will calculateand store the
checksum for outgoing packets sent on the socket and also verify the checksums for the
packetsreceivedon the socket.
Using IPv6 raw sockets,an applicationcan accessthe following information:
.
ICMPv6 messages
IPv6 header
Routing header
2.
Most ICMP packetsare passedto a RAW socket,after the kernel has finished processing
the ICMP message.Berkeley-derived implementationspassall receivedICMP packets
to a Raw socketother than Echo request,timestamprequestand addressmask request.
Thesethree ICMP messagesare processedentirely by the kernel.
3.
All IGMP packetsare passedto a RAW socket,after the kernel has finished processing
the IGMP message.
4.
All IP datagramswith a protocol field that the kernel doesnot understandare passedto
a raw socket.The only kernel processingdone on this packetsis the minimal verification
of someIP headerfields: the IP version,IPv4 headerchecksum,the headerlength and
the destinationIP address.
5.
If the datagramarrives in fragments,nothing is passedto the raw socketuntil all
fragments have arrived and have been reassembled.
When the kernel has an IP datagram to pass to a RAW sockets all Raw sockets for all
processesare examined, looking for all matching sockets.A copy of IP datagram is delivered
to eachmatching socket.
The following tests are performed for each raw socket and only if all three test are true
is the datagram delivered to the socket.
Advonced Sockels
4.55
l.
2.
If a local IP addressis bound to the raw socketby bind, then the destinationIp
addressof the received datagrammust match this bound address,or the datagram
is not delivered to the socket.
3.
If a foreign IP addresswas specified for the raw socket by connect, then the
sourceIP addressof the receiveddatagrammust match this connectedaddressor
the datagramis not deliveredto this socket.
If a raw socket is created with a protocol of zero, and neither bind nor connect is
called , then that socketreceivesa copy ofevery raw datagramthat the kernel passesto raw
sockets.
Whenever a received datagramis passedto a raw IPv4 socket, the entire datagram
including the IP headeris passedto the process.
I.
UDP/ TCP
2. Most ICMP
3. AII IGMP
RawSockets
4.10.1
protocolfield
bounddddr.= dest.lP
connected
dddr.= sourcelP
NetworkProgramming
and Management
Macro
Description
from beingpassedtc
Blocksall ICMPv6messages
an application.
typeis passedto
Returnstrue,if specifiedmessage
apDlication.
Ping program
o
o
routers,
betweentwo hosts(computers,
The ping utility testsresponsiveness
switches,etc.).Pingis usedprimarilyto find out if a computeris reachable.
It is often believedthat "Ping" is an abbreviationfor PacketInternet Groper
AdvoncedSockets
4.57
When the ping program gets an echo reply back from the remote host, it prints out the
response,giving severalpiecesof information:
1.
2.
3.
Round trip time it took for a packet to go to and from the remote host
4.
Every packet that gets sent out has a TTL field, which is set to a relatively high
number (ping packetsget a TTL of 255).
o As the packet travels over the network, the TTL field gets decreasedby one
for each node, server,or router it passesthrough.
o When the TTL drops to 0, the packet is discardedby the router.
o The main purposeof this is so that a packetdoesn'tlive forever on the network
and will eventuallydie when it is deemed"lost."
o If the TTL field variesin successivepings,it could indicatethat the successive
reply packetsare going via different routes.
o This could indicatethat certainnetwork routesmay be experiencingproblems.
r
o The time field is an indication of the round-trip time to get a packet to the
remote host.
o The reply is measuredin milliseconds.In general,it's best if round-trip times
are under 200 milliseconds.
o The time it takes a packet to reach its destinationis called latency.
If there is a large variance in the round-trip times, the network may be experiencing
problems.
4.58
NetworkProgramming
and Management
ICMPechorequest
<Wpe=128
, d e= 0 >
co
ICMPechoreply
< t y p e =1 2 9 c, o d e= 0 >
15 16
type
code
identifier
checksum
number
sequence
optionaldata
8 bytes
Fig 4.28 Format of ICMPv4 and ICMPv6 Echo request and Echo reply mess4Ses
Fromthe Fie.4.28;
TYpe- valuesfor ICMP messages.
, 4[ 0-Echoreply, 3- Destinationunreachable
l0- routersolicitation
Sourcequench, 5- redirect,8-Echo request,9-routerAdvertisement,
reply,l5 problem,l3-timestamp
request,14-timestamp
1I - time exceeded
, 12- parameter
informationrequest, 16-informationreply, l7- addressmaskrequest, I 8- addressmaskreply]
code is 0 and it containsthe error code for the datagramreportedon by this ICMP
type.
is dependent
uponthe message
message.
This interpretation
identifier -it is setto the processID of the Pingprocess
by one for eachpacketthat we send.
sequencenumber - is incremented
optional data - it is storedas 8 Bytetimestampwhenthepacketis sent.
by storing the timestampin thepacket when
RTT(RoundTrip time)-It is calculatetl
thereply is received.
The "ping" programcontainsa client interfaceto ICMP. It may be usedby a userto
verify an end-to-endInternetPathis operational.Theping programalsocollectsperformance
(i.e.themeasured
statistics
roundtrip timeandthenumberof timestheremoteserverfailsto
reply.
is received,
thepingprogramdisplaysa single
Eachtimean ICMP echoreplymessage
number,andthemeasured
line of text.The text printedby ping showsthereceivedsequence
roundtrip time (in milliseconds).
number(startingat 0) thatis incremented
containsa sequence
EachICMP Echomessage
after eachtransmission,and a timestampvalueindicatingthe transmissiontime.
Advonced Sockefs
4.59
in
Destination
ESsoecilied
lPprotocol
destination
payload
Server
copies
data
withthe
andreturns
a reply
source
anddestination
reversed
lPaddresses
Serverreceives
-/
echorcquesy'
test
icmpecho-feply
{4
sysais alive
Fig. 4.29 Use of the piug program to test whether tlte computer "syst" is operational.
The operation of ICMP is illustrated in the frame transition diagram shown above.In
this casethere is only one IntermediateSystem(IS) (router).
A version of the ping program works with both IPv4 and IPv6. We develop our own
program, insteadof presentingthe publicly availablesourcecode for two reasons.
o
The publicly available ping program suffers from a common Programming disease
know as creeping featurism: it supports a dozen different options Our goal in
examining a ping program is to understandthe network programming concepts
and techniques without being distracted with all these options. Our version of
Ping supports only one Option and is about five times smaller than the public
version.
the public version works with only IPv4 and we want to show a vision that also
supportsIPv6
The operation of ping is extremely simple: an ICMP echo request is sent to some IP
addressand that node respondswith an ICMP echo reply. Fig.4.30 shows the sampleoutput
of our ping program. It usesIPv4.
Solaris# pinggemini.tuc.noao.edu
PlNG gemini.tuc.
noao.edu (140,252.4.54)
:56databytes
64 bytesfrom 140.252.4.54:
seq=0,ttl=248,rtt=37.542ms
64 bytesfrom 140.252.4.54:
seq-1, ttl=248,rtt=34.596ms
64 bytesfrom 140.252.4.54:
seq=2,ttl=248,rtt=29.204ms
64 bytesfrom 140.252.4.54:
seq=3,ttl=248,rtt=52.630ms
Fig ,4.30 Sampleoutputfrom our ping program
4.60
NetworkProgramming
and Management
Establish
signalhandler
for SIGALRM ,^,
\
( sig_alrm )
.*.
v
r
hee
proc_v4
or
gv
Infinitereceiveloop
Fig.4.3l
2.
Fi9.4.32 shows our ping.h headerthat is included by all our program files.
#include "unp.h"
#include <netinet/in_systm.h>
#include < netinet/ip.h
>
#include <netinet/ip_icmp.h>
#defineBUFSIZE 1500
/* globals*/
char recvbufIBUFSIZE];
char sendbufIBUFSIZE];
int
char
int
pid_t
int
datalen;
*host;
nsent;
pid;
sockfd;
Advonced Sockets
16
4.61
int
verbose;
void
/* function prototypes */
proc_v4(char*, ssize_t,struct timeval ");
void
void
send_v4(void);
void
send_v6(void);
void
readloop(void);
void
sig_alrm(int);
void
struct proto {
void (*fproc)(char*, ssize_t,struct timeval *);
void (*fsend)(void);
s t r u c ts o c k a d d r * s a s e n d ;/ * s o c k a d d r { } f o r s e n d ,f r o m g e t a d d r i n f o* /
struct sockaddr *sarecv; /* sockaddr{} for receiving*/
socklen_t salen;
/ * l e n g t ho f s o c k a d d r { } s * /
i c m p p r o t o ; / * I P P R O T O _ x xvxa l u el o r I C M P* /
int
*pr;
)
#ifdef lPV6
#include "ip6.h"
#include
/ * s h o u l db e < n e t i n e t / i p 6 . h *>/
"icmp6.h"
/ * s h o u l d b e < n e t i n e t / i c m p 6 . h >* /
#endif
Fig.4.32ping.h header
The Basic IPv4 and ICMPv4 headersare included that define someglobal
variablesand our function prototypes.
4.62
Two headersare included that define the IPv6 and ICMPv6 structuresand
constants.
and Management
NetworkProgramming
t
int
c;
structaddrinfo*ai;
opterr= 0; /* don't wantgetopt0writingto stderr*/
while( (c = getopt(argc,
argv,"v"))l= -1) {
switch(c) {
case'v':
verbose+
+;
break;
case'?':
option:%c",c);
err_quit("unrecognized
)
)
if (optind!= argc-'l)
ping [-v ] <hostname>");
err_quit("usage:
=
host argv[optind];
pid = getpid0;
sig_alrm)
Signal(SIGALRM,
;
NULL,0, 0);
ai = Host_serv(host,
o/os
printf("PlNG
(%s):o/"ddalabytes\n",ai->ai_canonname,
datalen);
ai->ai_addrlen),
Sock_ntop_host(ai->ai_addr,
*/
protocol
accordingto
/* 4initialize
:= AF-INET)
if (ai->ai-family
{
pr : &proto_v4;
#ifdef lPV6
{
) elseif (ai->ai-family== AF-INETO)
pr = &proto_v6;
sockaddr-in6*)
if (lN6_lS_ADDR_V4MAPPED(&(((struct
ai->ai_addr)->sin6_addr)))
ping IPv4-mapped
IPv6address");
err_quit("cannot
#endif
) else
err_quit("unknown
addressfamily"/"d",ai-> ai-f amily);
=
pr->sasend ai->ai_addr;
= Calloc(1,
pr->sarecv
ai->ai_addrlen);
=
pr->salen ai->ai_addrlen;
readloop0;
exit(0);
)
mainfunction
Fi9.4.33
Advonced Sockcfs
4.63
'
The amount of optional data is set that gets sent with the ICMP echo requestto 56
bytes.
'
'
Any data that accompaniesan echo requestmust be sent back in the echo reply.
'
The time at which an echo requestis sendin the first 8 bytes of this data area is
storedand the RTT is calculatedand printed by using this when the echo reply is
received.
Processhostnameargument
o
'
The returned addrinfo structure contains the protocol family, either AF_INET or
AF-INET6
'
The pr global to the correct proto structureis initialized. An IPv6 addressis not
really an IPv4-mapped IPv6 addressby calling IN6_IS*ADDR_V4MAPPED,
becauseeventhoughthe returnedaddressis an IPv6 address,IPv4 packetswill be
sent to the host.
'
The socket address structure that has already been allocated by the getaddrinfo
function is used as the one for sending,and another socket addressstructure ofthe
samesize is allocated for receiving.
The function read loop is where the processingtakesplace and we show this Fig. 4.34
4.64
NetworkProgramming
and Management
#include "ping.h"
void
readloop(void)
f
I
int
size;
char
recvbuf
[BUFSIZE];
socklen_t len;
ssize_t
n;
structtimevaltval;
pr->icmpproto);
sockfd: Socket(pr->sasend->sa_family,
SOCK_RAW,
setuid(getuid0); /* don'tneedspecialpermissions
any more*/
*
*/
size= 60 1024; /* OK if setsockoptfails
setsockopt(sockfd,
SOL_SOCKET,
SO_RCVBUE
&size,sizeof(size));
sig_alrm(SIGALRM);/* sendfirstpacket*/
for(;;){
1sn: pr->salen;
n = recvfrom(sockfd,
recvbuf,sizeof(recvbuf),
0, pr->sarecv,
&len);
il(n<0){
if (errno== EINTR)
continue;
else
err_sys("recvfrom
error");
)
Gettimeofday(&tval,
NULL);
(*pr->fproc)(recvbuf,
n, &tval);
)
)
Fig. 4. 3 4 readI oop funct ion
Create socket
o
The call to setuid setsour effective user ID to our real user ID.
The program must have superuser privileges to createthe raw socket,but now
that the socket is created,and the extra privileges are given up.
By making the buffer large4 thereis a smaller chancethat the socket receive buffer
will overflow.
Advonced Sockets
4.65
Signal handler is called which sendsa packetand schedulesa SIGALRM for one
secondin future.
d s i g n a l h a n d l e r i s j u s t a C f u n c t i o n , e v e n t h o u g hi t i s n o r m a l l y c a l l e d
asynchronouslyby the kernel.
The main loop of the program is an infinite loop that readsall packetsreturnedon
the RAW ICMP sockets.
Gettimeofdayis called to record the time that the packet was received and then
call the appropriate protocol function(proc-v4 or proc-v6) to process ICMP
messages.
Fig .4.35 shows the proc_v4 function which processesall received ICMPv4 messages.
.
#include "ping.h"
*ptr,ssize-tlen,structtimeval*tvrecv)
void proc_v4(char
{
int
h l e n l ,i c m p l e n ;
rtt;
double
*ip;
structip
structicmp *icmp;
structtimeval*tvsend:
ip = (structip *) ptr; /* startof lP header'/
hlenl = ip->ip_hl<< 2; /* lengthof lP header*/
icmp= (structicmp*) (ptr + hlenl); /* startof ICMPheader*/
n l e n- h l e n l )< 8 )
i f ( ( i c m p l e=
(%d)< 8", icmplen);
err_quit("icmplen
== ICMP_ECHOREPLY)
if (icmp->icmp_type
{
!= Pid)
if (icmp->icmp_id
*/
return;
/" not a responseto our ECHO-REQUEST
if (icmplen< 16)
(%d)< 16",icmplen);
err_quit("icmplen
tvsend= (structtimeval") icmp->icmp_data;
tvsend);
tv_sub(tvrecv,
* 'l000.0+ tvrecv->tv_usec
/ 1000.0;
rtt = tvrecv->tv_sec
4.66
)
Fig.4.35 proc-v4 function:process ICMPv4 message
The IPv4 headerlength field is multiplied by four, giving the size of the IPv4
headerin bytes.
len
hlenl
icmplen
r.\-
header ICMPdata
lPv4header lPv4optionslCMPva
tl 2obyes
ip
o-40 t
l
icmP
If the messageis an ICMP echo reply then the identifier field is checkedto seeif
this reply is in responseto a requestthat our processsent.
[f the ping program is running multiple times on this host, each processgets a
copy of all received ICMP messages.
.
.
The RTT is calculatedby subtractingthe time the messagewas sent from the current
time.
The RTT is convertedfrom microsecondsto millisecondsand printed, along with
the sequencenumber field and the receivedTTL.
Advonced Sockets
4.67
If the user specified the -v commandline option, the type and code fields are
printed from all other receivedICMP messages.
h l e n 1i,c m p 5 l e n ;
double
rtt;
structip6_hdr *ip6;
structicmp6_hdr*icmp6;
structtimeval *tvsend:
ip6 = (structip6_hdr*) ptr;
/* startof lPv6header*/
hlen'l= sizeof(struct
ip6_hdr);
if (ip6->ip6_nxt
! = IPPROTO_ICMPV6)
err_quit("next
headernot IPPROTO_ICMPV6");
*) (ptr + hlenl);
icmp6= (structicmp6_hdr
: len - hlen'l)< 8)
if ( (icmp6len
(%d)< 8", icmp6len);
err_quit("icmp6len
== ICMP6_ECHO_REPLY)
if (icmp6->icmp6_type
{
t= pid)
if (icmp6->icmp6_id
4.68
NetworkProgramming
and Management
*/
return;
/* not a responseto our ECHO-REQUEST
if (icmp6len< 16)
(%d)< 16",icmp6len);
err_quit("icmp6len
tvsend= (structtimeval") (icmp6+ 1);
tv_sub(tvrecv,tvsend);
* 1000.0+ tvrecv->tv-usec/1000.0;
rtt = tvrecv->tv_sec
printf("o/od
bytesfrom 7os:seq=7otl,hlim=%d,rtt=%.3fms\n",
pr->salen)'
icmp6len,Sock-ntop-host(pr->sarecv,
ip6-> ip6_hlim,rtt);
icmp6-> icmp6_seq,
) elseif (verbose){
printf(" %d bytesfrom %s:type = %d,code = %d\n",
pr->salen),
icmp6len,
Sock-ntop-host(pr->sarecv,
icmp6->icmp6-code);
icmp6->icmp6_type,
)
*enart /* lPV6*/
)
Fig.4.38 Proc-v6function : process received ICMPv6 message.
The size ofthe IPv6 headeris fixed(40 bytes)and it is ensuredthat the next header
is ICMPv6.
len
hlenl
,
header
lCMPv6
lPv6header
tt 4obytes
ip6
tl
icmpGlen
ICMPdata
icmp
Fig.4.39 Headers, pointers and lengths in processittg ICMPv6 reply,
If the ICMP messagetype is an Echo reply, the identifier field is checkedto see
if the reply is received.
The RTT is calculated and then printed along with sequencenumber and the
IPv6 hop limit.
Advonced Sockets
4.69
If the user specifiedthe -v commandline option, the type and code fields are
printed from all other receivedICMP messages.
Our signal handler for the SIGALRM signal is the sig_alrm function shown in
fig.4.40.
o Our readloop calls this signal handleronce at the beginning to sendthe first
packet.
o
This function just calls the protocol dependentfunction to send an ICMP echo
request(send_v4or send_v6)and then schedulesanother SIGALRM for I
secondin the future.
#include "ping.h"
void
s i g _ a l r m ( i nst i g n o )
f
(*pr->fsend)0;
alarm(1);
return; /* probablyinterruptsrecvfromQ
I
4.70
NetworkProgramming
and Management
The identifier field is set to our processID and the sequencenumber field is set
to the global nsent, which is then incremented for the next packet.
The current day of time is stored in the data portion of the ICMP message.
The ICMPv4 cheksum is calculated from the ICMPv4 header and any data that
follows.
Send datagram
o
If IP_HDRINCL socket option is not set, then the kernel builds the IPv4 header
and prepends it to our buffer.
If the data length is an odd number,then one byte of zero is logically appended
to the end of the datajust for the checksumcomputation.
Unsignedshort
short*addr,int len)
in_cksum(unsigned
{
nleft= len;
int
int
sum = 0:
unsignedshort *w = addr;
unsignedshort answer= 0;
l*
'
(sum),we add
Our algorithmis simple,usinga 32 bit accumulator
.
sequential16 bit wordsto it, and at the end,fold backallthe
Advonced Sockets
4.71
'
carry bits from the top 16 bits into the lower 16 bits.
w h i l e ( n l e f t> 1 ) {
s u m+ = * w + + ;
nleft-= 2;
*/
/* 4mopup an odd byte,if necessary
if (nleft=: 1) {
*(unsigned
= *(unsigned
char")(&answer)
char")w ;
sum += answer:
The first while loop calculatesthe sum of all the l6 bit values.
If the length is odd, then the final byte is addedinto the sum.
'
This algorithm is fine for ping program but inadequatefor the high volumes of
checksumcomputationsperformedby the kernel.
The final function for our ping program is send_v6shown in fig.4.43 which builds and
sendsan ICMPv6 echo request.
#include "ping.h"
voidsend_v60
{
#ifdef lPV6
int
len;
structicmp6_hdr*icmp6;
icmp6= (structicmp6_hdr*) sendbuf;
= ICMP6_ECHO_REOUEST;
icmp6->icmp6_type
= O;
icmp6->icmp6_code
=
icmp6->icmp6_idpid;
= rsaflt* *i
icmp6->icmpo_seq
Gettimeofday((struct
timeval*) (icmp6+ 1), NULL);
=
len 8 + datalen; /* 8-bytelCMPvoheader*/
Sendto(sockfd,
sendbuf,len,0, pr->sasend,pr->salen);
4kernel
calculates
and storeschecksumfor us */
l*
#endif l* lPV6*l
l
Fig.4.43 send_v6function:build and send an ICMPv6 echo request messege
4.72
NetworkProgramming
and Management
This function is similar to send v4 but in that it does not compute the ICMPv6
checksum.
Introduction
In this caseusing the tracerouteutility can show the location right before the
host that's not resPonding'
The packet then gets transferred to the first router (completing the first hop), and
the TTL gets decrementedby the router from I to 0.
The router then discards the packet and sendsoff an ICMP notification packet to
the original host with the messagethat the TTL expired from the router.
This tells tracert what the first hop is and how long it takes to get there.
Traceroute repeatsthis, gradually incrementing the TTL until a path to the remote
host is traced and it gets back an ICMP Port Unreachablemessage,indicating that
the remote host has been reached.
Advonced Sockets
4.73
The sender manipulates the TTL (hop count) value at the IP layer to force each
hop in turn to return an error message
Traceroute is a computer network tool used to determine the route taken by packets
acrossan IP network. An IPv6 variant. traceroute6. is also widely available.
4.12.2
Uses
By showing a list of routers traversed,it allows the user to identify the path
taken to reach a particular destination on the network.
This can help identify routing problemsor firewalls that may be blocking access
to a site. Tracerouteis also usedby penetrationtestersto gather information
about network infrastructure and IP ranges around a given host.
NetworkProgramming
and Management
void sig_alrm(int);
void traceloop(void);
timeval*, structtimeval*);
void tv-sub(struct
structproto {
char *("icmpcode)(int);
structtimeval*);
int (*recv)(int,
getaddrinfo*/
structsockaddr*sasend;/"sockaddr{}for send,from
*/
*sarecv;
/* sockaddr{}lor receiving
structsockaddr
*/
structsockaddr*salast;/* lastsockaddr{}lor receiving
*sabind;
port *i
source
binding
for
/* sockaddr{}
structsockaddr
*/
salen; /* lengthof sockaddr{}s
socklen-t
valuefor ICMP*i
icmpproto;/* IPPROTO-xxx
int
level
to set TTL*/
int ttllevel;
/* setsockopt0
nameto set TTL*/
int ttloptname, /* setsockoptQ
'pr;
)
#ifdef lPV6
*/
/* shouldbe <netinet/ip6.h>
#include "ip6.h"
*/
"icmp6.h"
/* shouldbe <netinet/icmp6.h>
#include
#endif
Fig.4.44 Trace.h header
IncludeIPv4 headers
o
o
The standardIPv4 headersare includedthat define the IPv4 ,ICMPv4 and UDP
andconstants.
structures
The rec structuredefinesthe dataportion of the UDP datagramthat is send,but
purposes.
It is sentmainlyfor debugging
to be examined.
thedatais not necessary
Defineproto Structure
o
includeIPv6 headers
o
4.75
#include "trace.h"
structproto proto_v4={icmpcode_v4,
recv_v4,
NULL,NULL,NULL,NULL,0,
TPPROTO_|CMB
TPPROTO_|B
rP_TTL);
#ifdef lPV6
structproto proto_v6= { icmpcode_v6,
recv_v6,NULL,NULL,NULL,NULL,0,
IPPROTO_ICM
PV6,IPPROTO_|
PV6,IPV6_U
NrCAST_HOPS
);
#endif
int datalen= sizeof(struct
rec); /* defaults*/
int max_ttl= 30;
int nprobes= 3;
u_shortdport = 32768+ 666;
int
main(intargc,char**argv)
int
c;
structaddrinfo*ai;
opterr: 0; /* don't wantgetopt0writingto stderr*/
while( (c = getopt(argc,
argv,"m:v"))!= -1) {
switch(c) {
case'm':
if ( (max_ttl= atoi(optarg))
<= 1)
-m value");
err_quit("invalid
break;
case'v':
verbose+ + ;
break;
case'?':
err_quit("
unrecognized
option: o/oc",
c)i
)
)
if (optindl= argc-1)
err_quit("usage:
traceroute[ -m <maxttl>-v ] <hostnamet");
host = argv[optind];
pid = getpid$;
. Signal(SIGALRM,
sig_alrm);
ai = Host_serv(host,
NULL,0, 0);
printf("traceroute
to %s (7os):7odhops max,o/oddata bytes\n",
ai-> ai_canonname,
Sock_ntop_host(ai> ai_addr,ai-> ai_addrlen),
max_ttl,datalen);
/* initializeaccordingto protocol*/
== AF_INET)
if (ai->ai_family
{
pr : &proto_v4;
#ifdef lPV6
== 1p_;11ET6)
) elseif (ai->ai_family
{
pr = &proto_v6;
*)ai-> ai_addr).
if (lN6_lS_ADDR_V4MAPPED(&(((struct
> sin6_addr)))
sockaddr_in6
ping lPv4-mapped
err_quit("cannot
lPv6address");
#endif
) else
err_quit("unknownaddressfamily o/"d",ai-> ai_family);
pr->sasend= ai->ai_addr;
4.76
address*/
/* containsdestination
NetworkProgrammingand Management
p r - > s a r e c v= C a l l o c ( 1 ,a i - > a i _ a d d r l e n ) ;
p r - > s a l a s t= C a l l o c ( 1, a i - > a i _ a d d r l e n ) ;
p r - > s a b i n d= C a l l o c ( 1 ,a i - > a i _ a d d r l e n ) ;
p r - > s a l e n= a i - > a i _ a d d r l e n ;
traceloop0;
exit(0);
Defineproto structures
The two proto structuresaredefined,one for IPv4 and one for IPv6, althoughthe
arenot allocateduntil the endof this function.
pointerto the socketaddressstructures
SetDefaults
.
The maximum TTL or Hop limit that the program usesdefaults 230.
For each TTL three probe packetsare sent but this could be changedwith
anothercommandline option.
The intial destinationport is 32768+ 666 and this will be incrementedby one
each time a UDP datagramis sent.
AdvoncedSockefs
4.77
"trace.h"
#include
void
traceloop(void)
t
int
seq,code, done;
rtt;
double
*rec:
struct rec
struct timeval
tvrecv;
recvfd = Socket(pr-> sasend-> sa_family,SOCK_RAW,pr-> icmpproto);
s e t u i d ( g e t u i d 0 ) ; / * d o n ' t n e e d s p e c i a lp e r m i s s i o n sa n y m o r e * /
s e n d f d = S o c k e t ( p r - > s a s e n d - > s a _ f a m iS
l yO, C K _ D G R A M0,) ;
pr-> sabind-> sa_family= pr-) sosnd-> sa_family;
sport = (getpid0 & oxffff) | 0x8000; /* our source UDP porl# *l
s o c k _ s e t _ p o r t ( p r - > s a b i npdr,- > s a l e n ,h t o n s ( s p o r t ) ) ;
B i n d ( s e n d l dp
, r - > s a b i n d ,p r - > s a l e n ) ;
sig_alrm(SIGALRM);
seq = 0'
done = 0;
f o r ( t t l= 1 ; t t l < = m a x _ t t&
l & done == 0;ttl++) {
Setsockopt(sendfd,pr->ttllevel,pr->ttloptname,&ttl, sizeof(int));
bzero(pr-> salast, pr-> salen);
p r i n t f ( " % 2 d" , t t l ) ;
f fl u s h ( s t d o u t ) ;
f o r ( p r o b e = 0 ; p r o b e < n p r o b e s ;p r o b e + + ) {
yss = (struct rec *) sendbul;
r e c - > r e c _ s e q= + + s e q ;
rec->rec_ttl = ttl;
> rec_tv,NULL);
Gettimeofday(&recpr->salen, htons(dport + seq));
sock_set_port(pr->sasend,
S e n d t o ( s e n d f ds, e n d b u f ,d a t a l e n ,0 , p r - > s a s e n d ,p r - > s a l e n ) ;
if ( (code = (*pr->recv)(seq,&tvrecv))== -3;
p r i n t f ( "* " ) '
/ * t i m e o u t ,n o r e p l y * /
else {
char strINI_MAXHOST];
if (sock_cmp_addr(pr->sarecv,
pr->salast,pr->salen) !: 0) {
pr->salen, str, sizeof(str),
if (getnameinfo(pr->sarecv,
N U L L , 0 , 0 )= = g ;
printf(" %s (o/os)",
str,
> sarecv,pr-> salen));
Sock_ntop_host(prelse
printf(" 7os",
pr->salen));
Sock_ntop_host(pr->sarecv,
p
r
>
s
a
r
e
c
v
p
,
r
>
salen);
memcpy(pr->salast,
)
tv_sub(&tvrecv,&rec-> rec_tv);
rtt = tvrecv.tv_sec* 1000.0 + tvrecv.tv_usec/ 1000.0;
printf(" %.31ms", rtt);
if (code == -1) /* port unreachable;at destination*/
d o n e ++ :
4.78
NetworkProgramming
and Management
The maximum TTL or Hop limit that the program usesdefaults 230.
For each TTL threeprobe packetsare sent but this could be changedwith
anothercommandline option.
The intial destinationport is 32768+ 666 and this will be incrementedby one
each time a UDP datagramis sent.
Advonced Sockets
4.77
elseif (code> = 0)
printf("(ICMP%s)",(*pr->icmpcode)(code));
)
fflush(stdout);
)
printf("\n");
i
Fig.4.46 Traceloopfunction : main processing loop.
Createtwo sockets
.
Two socketsare needed:a raw socketon which all returnedICMP are readanda
Udp socketon which a probepacketsare sentwith the increasingTTLs.
Advonced Sockcls
4.79
If this is a first reply for a given TTL or if the IP addresssof the node sendingthe
ICMP messagehas changedfor the TTL,the host name and IP addresssare printed.
The RTT is calculatedas the time difference from when the probe is sent to the
time the ICMP messageis returnedand printed.
Our recv_v4 function is shown inthe fig.4.47
#include "trace.h"
* Return:
-3 on timeout
*
-2 on ICMPtimeexceeded
in transit(callerkeepsgoing)
*
-1 on ICMPportunreachable
(calleris done)
int
recv_v4(int
seq,structtimeval*tv)
{
int
h l e n 1h, l e n 2i,c m p l e n ;
socklen_t len;
ssize_t
n;
*ip, *hip;
structip
structicmp *icmp;
structudphdr *udp;
alarm(3);
for(;;){
;gn = pr->salen;
n = recvfrom(recvfd,
recvbuf,sizeof(recvbuf),
0, pr->sarecv,
&len);
i f ( n < 0 ){
if (errno== EINTR)
return(-3); l* alarmexpired*/
else
4.80
NetworkProgramming
and Management
err_sys("
recvfrom error");
I
*/
Gettimeofday(tv,NULL); /* get time of packet arrival
*/
*)
=
lP
header
(struct
start
of
ip
recvbuf;
ip
/*
*/
h l e n l = i p - > i p _ h l < < 2 ; / * l e n g t ho f l P h e a d e r
*)
(recvbuf + hlenl); /* start of lcMP header */
icmp (struct icmp
=
if ( (icmplen n hlenl) < 8)
e r r _ q u i t ( " i c m p l e(n% d ) < 8 " , i c m p l e n ) ;
D&
i f ( i c m p - > i c m p _ t y p e= = I C M P - T I M X C E E &
i c m p - > i c m p _ c o d e= = l c M P _ T I M X C E E D _ I N T R A N{ S )
if(icmplen<8+20+8)
e r r _ q u i t ( " i c m p l e(n% d ) < 8 + 2 0 + 8 " , i c m p l e n ) ;
hip = (structip *) (recvbuf + hlenl + 8);
h l e n 2 = h i p - > i p _ h l< < 2 ;
u d p = ( s t r u c tu d p h d r * ) ( r e c v b u f+ h l e n l + 8 + h l e n 2 ) ;
&&
i f ( h i P - > i P - P= = I P P R O T O - U D P
)&
u d p - > u h _ s P o r t: : h t o n s ( s P o r t&
u d p - > u h _ d p o r t= = h t o n s ( d p o r t+ s e q ) )
return(-2); /* we hit an intermediaterouter */
) e l s e i f ( i c m p - > i c m p _ t y p e= = I C M P - U N R E A C H{)
if(icmplen<8+20+8)
e r r _ q u i t ( " i c m p l e(n% d ) < 8 + 2 0 + 8 " , i c m p l e n ) ;
h i p = ( s t r u c ti p " ) ( r e c v b u f+ h l e n l + 8 ) ;
h l e n 2= h i p - > i p _ h l< < 2 ;
u d p = ( s t r u c tu d p h d r * ) ( r e c v b u f+ h l e n l + 8 + h l e n 2 ) ;
&&
i f ( h i P - > i P - P= = I P P R O T O - U D P
)&
u d p - > u h _ s p o r t: = h t o n s ( s p o r t &
u d p - > u h _ d p o r t= = h t o n s ( d p o r t+ s e q ) ) {
i l ( i c m p - > i c m p _ c o d e= = I C M P - U N R E A C H - P O R T )
r e t u r n ( - 1 )/;" h a v e r e a c h e dd e s t i n a t i o n* /
else
r e t u r n ( i c m p - > i c m p _ c o d e )/ ;* 0 , 1 , 2 , . . . ' l
)
) else if (verbose){
printf(" (from %s: type : %d, code = o/od)\n",
pr->salen),
Sock_ntop_host(pr->sarecv,
i c m p -> i c m p _ t y p e ,i c m p - >i c m p _ c o d e;)
)
*/
/* Some other ICMP error, recvfrom$ again
) )
Fig.4.47 recv-v4funclion: readand processICMPv4nrcssages
Set alarm and read each ICMP
message
An alarmis set for 3 secondsin the futureand the functionentersa loop that calls
returnedon the raw socket.
recvfrom,readingeachICMPv4message
Get pointer to ICMP header
ip pointsto the beginningof the IPv4headerandicmp pointsto the beginningof the
ICMP header.
pointers,andlengthsusedby the code'
Fig.4.48showsthe variousheaders,
AdvoncedSockels
4.81
n
icmplen
hlen2
hlenl
lPv4
ICMP4
lPv4
header options header
fzo
ovtes o-40
ip
i cmp
lPv4
lPv4
h e a d e r options
t z o
hip
F--
o-40 t
I
UDP
header
udp
lPv4datagramthat
generated
the ICMP
error
int
4.82
NetworkProgramming
and Management
seq,structtimeval*tv)
recv_v6(int
#ifdef lPV6
hlen'|,hlen2,icmP6len;
int
n;
ssize_t
len;
socklen_t
structip6_hdr *ip6,*hiP6;
structicmp6_hdr*icmP6;
structudphdr *udp;
alarm(3);
for(;;){
len = pr->salen;
&len);
0, pr->sarecv,
recvbuf,sizeof(recvbuf),
n = recvfrom(recvfd,
if(n<0){
if (errno== EINTR)
return(-3); /* alarmexPired*/
else
recvfrom error");
err_sys("
)
NULL); /* get time of packetarrival*/
Gettimeofday(tv,
*/
ip6 = (structip6-hdr*) recvbuf; /r startof lPv6header
ip6_hd0;
hlenl = sizeof(struct
*) (recvbuf+ hlenl);/* ICMPhdr */
=
(struct
icmp6-hdr
icmp6
= n - hlenl) < 8)
il ( (icmp6len
(%d)< 8", icmp6len);
err_quit("icmp6len
= = ICMP6-TIME-EXCEEDED
&&
(icmp6->icmp6-type
if
==
ICMP6-TIME-EXCEED-TRANSIT)
icmp6->icmp6-code
{
if(icmp6len<8+40+8)
(%d)< I + 40 + 8", icmp6len);
err_quit("icmp6len
=
hip6 (structip6_hdr*) (recvbuf+ hlenl + 8);
ip6_hdr);
hlen2= sizeof(struct
udp = (structudphdr*) (recvbuf+ hlenl + I + hlen2);
:= IPPROTO-UDP
&&
if (hip6->ip6-nxt
:= htons(sPort)
&&
udp->uh_sport
== htons(dport
+ seq))
udp->uh_dport
router*/
return(-2); /* we hit an intermediate
==
{
) elseif (icmp6->icmp6-type ICMP6-DST-UNREACH)
if(icmpOlen<8+40+8)
(%d)< 8 + 40 + 8", icmp6len);
err_quit("icmp6len
hip6 = (structip6_hdr*) (recvbuf+ hlenl + 8);
hlen2= 40;
udp - (structudphdr*) (recvbuf+ hlenl + 8 + hlenz);
== IPPROTO-UDP
&&
if (hip6->ip6_nxt
== htons(sPort)
&&
udp->uh_sport
== htons(dport
+ seq)){
udp->uh_dport
= : ICMP6-DST-UNREACH-NOPORT)
if (icmp6->icmp6-code
*/
return(-1);
/* havereacheddestination
else
return(icmp6->icmp6_code);
/* 0, 1,2, ... *l
AdvoncedSockets
4.83
) else if (verbose){
printf(" (from %s: type = %d, code = %d)\n",
sarecv,pr->salen),
Sock_ntop_host(pr->
icmp6-> icmp6_type,icmp6-> icmp6-code);
lt
*/
/* Some other ICMP error, recvfromQagain
l
#endif
)
Fig.4.49 recv_v6 function: read and process ICMPv6 messoges.
This function is nearly identical to recv_v4. except for the different constant
namesand the different structuremembernames.Also the size of the IPv6 headeris a
fixed 40 bytes; while with IPv4 the headerlength field is fetched and multiply it by 4 to
accountfor any IP options. Fig.4.50 showsvarious headers,pointer and lengthsusedby
the code.
icmolen
hlenl
lPv4
UDP
lPv4
ICMP4 lPv4
lPv4
header options header header options header
oytes o-40 t
fzo
l
l
icmp
ip
t
hip
I
I
20
o-40 t
udp
that
lPv4datagram
generated
thelcMP
error
4,84
NetworkProgramming
and Management
#include
char*
"trace.h
icmpcode_v6(intcode)
t
switch(code){
REACH-NOROUTE:
case ICMP6-DST-UN
routeto host");
return("no
:
REACH-ADMIN
case ICMP6-DST-UN
prohibited")
;
return("administratively
case ICMP6-DST-UNREACH-NOTNEIGHBOR:
a neighbor");
return("not
REACH-ADDR:
case ICMP6-DST-UN
;
return("addressunreachable")
case ICMP6-DST-UNREACH-NOPORT:
unreachable")
;
return("Port
default:
")
return("
Iunknowncode] ;
)
I
*/
return; /* just interruptthe recvfrom0
)
F ig.4. 5 2 sig-al rnr funct ion
All this function does is return, causing an error return of EINTR from the recvfrom in
either recv v4 or recv v6.
AdvoncedSockeis
4.85