You are on page 1of 32

UNIT 3

SOCKET OPTIONS AND ELEMENTARY UDP SOCKETS


Socket options – getsocket and setsocket functions – generic socket options – IP socket
options – ICMP socket options - TCP socket options – Elementary UDP sockets – UDP
Echo server – UDP echo client – Multiplexing TCP and UDP sockets – Domain Name
System – gethostbyname function – Ipv6 support in DNS – gethostbyaddr function –
getservbyname and getservbyport function.
1. Socket options
Various socket options are used to control the socket operations
There are various ways to get and set the socket options:
The getsockopt and setsockopt functions
The fcntl function
The ioctl function
getsockopt is used to get the current value of a socket options.
setsocketopt is used to set the value of a socket option.
fcntl stands for file control. This function performs various descriptor control operations
such as
Setting non blocking I/O
Setting signal driven I/O.
Getting and setting socket owner.
2. getsocket and setsocket functions
getsocket function
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
return: 0 if OK,–1 on error
sockfd must refer to an open socket descriptor.
level indicates whether the socket options is generic or protocol-specific.
optval is a pointer to a variable into which the current value of the option is stored by
getsockopt( ).
optlen is the size of optval.
setsocket function
#include <sys/socket.h>
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
sockfd must refer to an open socket descriptor.
level indicates whether the socket options is generic or protocol-specific.
optval is a pointer to a variable from which the new value of the option is fetched by
setsockopt.
optlen is the size of optval.
3. Generic socket options
Generic socket options are protocol-independent.
Some of the options apply to only certain types of sockets.
For example, the SO_BROADCAST socket option is called "generic," it applies only to
datagram sockets.
SO_BROADCAST Socket Option
This option enables or disables the ability of the process to send broadcast messages.
This option is supported only for datagram sockets and only on networks that support the
concept of a broadcast message (e.g., Ethernet, token ring, etc.).
Since an application must set this socket option before sending a broadcast datagram, it
prevents a process from sending a broadcast when the application was never designed to
broadcast.
Rather than forcing the application to try to determine if a given address is a broadcast
address or not, the kernel will test that.
If the destination address is a broadcast address and this socket option is not set, EACCES
is returned.
SO_DEBUG Socket Option
This option is supported only by TCP.
When this option is enabled, the kernel maintains detailed information about all the packets
sent or received by TCP for the socket.
These are kept in a circular buffer within the kernel that can be examined with the trpt
program.
SO_DONTROUTE Socket Option
This option specifies that outgoing packets are to bypass the normal routing mechanisms of
the underlying protocol.
The packet is directed to the appropriate local interface. If the local interface cannot be
determined from the destination address, ENETUNREACH is returned.
The equivalent of this option can also be applied to individual datagrams using the
MSG_DONTROUTE flag with the send, sendto, or sendmsg functions.
This option is often used by routing daemons (e.g., routed and gated) to bypass the routing
table and force a packet to be sent out a particular interface.
SO_ERROR Socket Option
When an error occurs on a socket, the protocol in kernel sets a variable named so_error for
that socket to one of the standard Unix values. This is called the pending error for the
socket.
The process can be immediately notified of the error in one of two ways:
1. If the process is blocked in a call to select on the socket , for either readability or
writability, select returns with either or both conditions set.
2. If the process is using signal-driven I/O, the SIGIO signal is generated for either the
process or the process group.
The process can then obtain the value of so_error by fetching the SO_ERROR socket
option. The integer value returned by getsockopt is the pending error for the socket.
The value of so_error is then reset to 0 by the kernel .
If so_error is nonzero when the process calls read and there is no data to return, read
returns–1 with errno set to the value of so_error.
The value of so_error is then reset to 0. If there is data queued for the socket, that data is
returned by read instead of the error condition.
If so_error is nonzero when the process calls write, –1 is returned with errno set to the
value of so_error is reset to 0.
SO_KEEPALIVE Socket Option
When a keep-alive option is set for a TCP socket and no data has been exchanged across
the socket in either direction for two hours, TCP automatically sends a keep-alive probe to
the peer.
This probe is a TCP segment to which the peer must respond. One of three scenarios
results:
1. The peer responds with the expected ACK. The application is not notified. TCP will send
another probe following another two hours of inactivity.
2. The peer responds with an RST, which tells the local TCP that the peer host has crashed
and rebooted. The socket's pending error is set to ECONNRESET and the socket is
closed.
3. There is no response from the peer to the keep-alive probe. If there is no response at all to
TCP's keep-alive probes, the socket's pending error is set to ETIMEDOUT and the socket
is closed. But if the socket receives an ICMP error in response to one of the keep-alive
probes, the corresponding error is returned. A common ICMP error in this scenario is
"host unreachable," indicating that the peer host is unreachable; the pending error is set to
EHOSTUNREACH. This can occur either because of a network failure or because the
remote host has crashed.
The purpose of this option is to detect if the peer host crashes or becomes unreachable.
If the peer process crashes, its TCP will send a FIN across the connection, which we can
easily detect with select.
If there is no response to any of the keep-alive probes (scenario 3), we are not guaranteed
that the peer host has crashed, and TCP may well terminate a valid connection.
This option is normally used by servers, although clients can also use the option.
Server use the option because they spend most of their time blocked waiting for input
across the TCP connection that is, waiting for a client request.
But if the client host's connection drops, is powered off, or crashes, the server process will
never know about it, and the server will continually wait for input that can never arrive.
This is called a half-open connection. The keep-alive option will detect these half-open
connections and terminate them.
SO_LINGER Socket Option
This option specifies how the close function operates for a connection-oriented protocol.
By default, close returns immediately, but if there is any data still remaining in the socket
send buffer, the system will try to deliver the data to the peer.
The SO_LINGER socket option lets us change this default. This option requires the
following structure to be passed between the user process and the kernel. It is defined by
including <sys/socket.h>.
struct linger
{
int l_onoff; /* 0=off, nonzero=on */
int l_linger; /* linger time, POSIX specifies units as seconds */
};
Calling setsockopt leads to one of the following three scenarios, depending on the values of
the two structure members:
1. If l_onoff is 0, the option is turned off. The value of l_linger is ignored and close returns
immediately.
2. If l_onoff is nonzero and l_linger is zero, TCP terminates the connection when it is closed
TCP discards any data still remaining in the socket send buffer and sends an RST to the
peer, not the normal four-packet connection termination sequence.
3. If l_onoff is nonzero and l_linger is nonzero, then the kernel will linger when the socket
is closed. That is, if there is any data still remaining in the socket send buffer, the process
is put to sleep until either: (i) all the data is sent and acknowledged by the peer TCP, or
(ii) the linger time expires.
Figure: Default operation of close: it returns immediately.

We assume that when the client's data arrives, the server is temporarily busy, so the data is
added to the socket receive buffer by its TCP.
FIN is also added to the socket receive buffer. By default, the client's close returns
immediately. The client's close can return before the server reads the remaining data in its
socket receive buffer.
It is possible for the server host to crash before the server application reads this remaining
data.
The client can set the SO_LINGER socket option, specifying some positive linger time.
When this occurs, the client's close does not return until all the client's data and its FIN
have been acknowledged by the server TCP.
Figure . close with SO_LINGER socket option set and l_linger a positive value.

The basic principle here is that a successful return from close, with the SO_LINGER socket
option set, only tells us that the data we sent have been acknowledged by the peer TCP.
This does not tell us whether the peer application has read the data.
If we do not set the SO_LINGER socket option, we do not know whether the peer TCP has
acknowledged the data.
One way for the client to know that the server has read its data is to call shutdown (with a
second argument of SHUT_WR) instead of close and wait for the peer to close its end of
the connection.
Figure. Using shutdown to know that peer has received our data.

SO_LINGER socket option is set, the return can occur at three different times:
1. close returns immediately, without waiting at all
2. close lingers until the ACK of our FIN is received.
3. shutdown followed by a read waits until we receive the peer's FIN.

SO_OOBINLINE Socket Option


When this option is set, out-of-band data will be placed in the normal input queue.
SO_RCVBUF and SO_SNDBUF Socket Options
Every socket has a send buffer and a receive buffer.
The receive buffers are used by TCP and UDP to hold received data until it is read by the
application.
With TCP, the available room in the socket receive buffer limits the window that TCP can
advertise to the other end.
The TCP socket receive buffer cannot overflow because the peer is not allowed to send
data beyond the advertised window.
This is TCP's flow control, and if the peer ignores the advertised window and sends data
beyond the window, the receiving TCP discards it.
With UDP, when a datagram arrives that will not fit in the socket receive buffer, that
datagram is discarded.
SO_RCVBUF & SO_SNDBUF is used to change the default size of receive and socket
send buffer.
When setting the size of the TCP socket receive buffer, the ordering of the function calls is
important.
This is because of TCP's window scale option is exchanged with the peer on the SYN
segments when the connection is established.
For a client, this means the SO_RCVBUF socket option must be set before calling connect.
For a server, this means the socket option must be set for the listening socket before
calling listen.
The TCP socket buffer sizes should be at least four times the MSS for the connection.
SO_RCVLOWAT and SO_SNDLOWAT Socket Options
Every socket has a receive low-water mark and a send low-water mark.
These two socket options allow us to change these two low-water marks.
The receive low-water mark is the amount of data that must be in the socket receive buffer
for read.
The send low-water mark is the amount of available space that must exist in the socket
send buffer for writing.
This low-water mark normally defaults to 2,048 for TCP sockets.
SO_RCVTIMEO and SO_SNDTIMEO Socket Options
These two socket options allow us to place a timeout on socket receives and sends.
The timeouts is represented in seconds and microseconds.
We disable a timeout by setting its value to 0 seconds and 0 microseconds.
The receive timeout affects the five input functions: read, readv, recdv, recvfrom, and
recvmsg.
The send timeout affects the five output functions: write, writev, send, sendto, and
sendmsg.
SO_REUSEADDR and SO_REUSEPORT Socket Options
The SO_REUSEADDR socket option serves four different purposes:
1. It allows a listening server to start and bind its well-known port, even if previously
established connections exist that use this port as their local port. This condition is
encountered as follows:
a. A listening server is started.
b. A connection request arrives and a child process is generated to handle that client.
c. The listening server terminates, but the child continues to service the client on the
existing connection.
d. The listening server is restarted.
By default, when the listening server is restarted by calling socket, bind, and listen, the
call to bind fails.
But if the server sets the SO_REUSEADDR socket option between the calls to socket and
bind, the latter function will succeed.
2. SO_REUSEADDR allows multiple instances of same server to be started on the same
port, as long as each instance binds a different local IP address.
3. This function allows a single process to bind the same port to multiple sockets, as long as
each bind specifies a different local IP address.
4. SO_REUSEADDR allows completely duplicate bindings: a bind of an IP address and
port, when that same IP address and port are already bound to another socket.
SO_REUSEADDR socket option should be set before calling bind in TCP servers.
When writing a multicast application that can be run multiple times on the same host at the
same time, set the SO_REUSEADDR socket option and bind the group's multicast address
as the local IP address.
SO_REUSEPORT & SO_REUSEADDR is used for the socket that wants to bind same IP
address and port number.
SO_REUSEPORT
This option is used for AF_INET.
It allows multiple processes to share a port. All incoming multicast datagrams that are
designed for the port are delivered to all sockets that are bound to the port.
All processes that share the port must specify this option.
SO_TYPE Socket Option
This option returns the socket type. The integer value returned is a value such as
SOCK_STREAM or SOCK_DGRAM.
SO_USELOOPBACK Socket Option
This option applies only to sockets in the routing domain (AF_ROUTE). This option
defaults to ON for these sockets. When this option is enabled, the socket receives a copy of
everything sent on the socket. Another way to disable these loopback copies is to call shutdown
with a second argument of SHUT_RD.
4. IP socket options
These socket options are processed by IPv4 and have a level of IPPROTO_IP.
IP_HDRINCL Socket Option
If this option is set for a raw IP socket we must build our own IP header for all the
datagrams we send on the raw socket.
When this option is set, we build a complete IP header, with the following exceptions:
IP always calculates and stores the IP header checksum.
If we set the IP identification field to 0, the kernel will set the field.
If the source IP address is INADDR_ANY, IP sets it to the primary IP address of the
outgoing interface.
Setting IP options is implementation-dependent. Some implementations take any IP
options that were set using the IP_OPTIONS socket option and append these to the
header that we build, while others require our header to also contain any desired IP
options.
IP_OPTIONS Socket Option
Setting this option allows us to set IP options in the IPv4 header. This requires intimate
knowledge of the format of the IP options in the IP header.
IP_RECVDSTADDR Socket Option
This socket option causes the destination IP address of a received UDP datagram to be
returned as ancillary data by recvmsg.
IP_RECVIF Socket Option
This socket option causes the index of the interface on which a UDP datagram is received
to be returned as ancillary data by recvmsg.
IP_TOS Socket Option
This option allows us to set the type-of-service (TOS) in the IP header for a TCP or UDP
socket.
If we call getsockopt for this option, the current value that would be placed into TOS field
in the IP header (which defaults to 0) is returned. There is no way to fetch the value from a
received IP datagram.
We can set the TOS to one of the constants shown in the table, which are defined by
including <netinet/in.h>
Constant Description
IPTOS_LOWDELAY Minimum delay
IPTOS_THROUGHPUT Maximize throughput
IPTOS_RELIABILITY Maximize reliability
IPTOS_LOWCOST Minimize cost

IP_TTL Socket Option


With this option, we can set and fetch the default TTL (Time to Live) that the system will
use for a given socket.
As with the TOS field, calling getsockopt returns the default value of the field that the
system will use in outgoing datagrams—there is no way to obtain the value from a received
datagram.
5. ICMP socket options
This socket option is processed by ICMPv6 and has a level of IPPROTO_ICMPv6.
ICMP6_FILTER Socket Option
This option allow us to fetch and set an icmp6_filter structure that specifies which of the
256 possible ICMPv6 message types will be passed to the process on a raw socket.
6. TCP socket options
There are two socket options for TCP. We specify the level as IPPROTO_TCP.
TCP_KEEPALIVE Socket Option
It specifies the idle time in seconds for the connection before TCP starts sending keepalive
probe.
The default value must be at least 7200 seconds, which is 2 hours.
This option is effective only when the SO_KEEPALIVE socket option is enabled.
TCP_MAXRT Socket Option
It specifies the amount of time in seconds before a connection is broken once TCP starts
retransmitting data.
A value of 0 means use the system default & a value of -1 means retransmit forever.
If a positive value is specified it may be rounded up to the implementations next
retransmission time.
TCP_MAXSEG Socket Option
This socket option allows us to fetch or set the MSS (Maximum Segment Size) for a TCP
connection.
The value returned is the maximum amount of data that our TCP will send to the other end.
The MSS announced by the other end with its SYN.
If this value is fetched before the socket is connected, the value returned is the default value
that will be used if an MSS option is not received from the other end.
The maximum amount of data that our TCP will send per segment can also change during
the life of a connection if TCP supports path MTU discovery.
Once the connection is established, this value is the MSS option announced by the peer,
and we cannot exceed that value.
TCP_NODELAY Socket Option
If this option is set, it disables TCP's Nagle algorithm.
The purpose of the Nagle algorithm is to reduce the number of small packets.
The algorithm states that if a given connection has outstanding, then no small packets will
be sent on the connection in response to a user write operation until the existing data is
acknowledged.
The definition of a "small" packet is any packet smaller than the MSS.
TCP will always send a full-sized packet.
The purpose of the Nagle algorithm is to prevent a connection from having multiple small
packets outstanding at any time.
Example: We type the six-character string "hello!" to client with exactly 250 ms between
each character. The RTT to the server is 600 ms and the server immediately sends back the
echo of each character. Each character is sent in a packet by itself: the data segments from
left to right, and the ACKs from right to left.
If the Nagle algorithm is enabled (the default), we have the eight packets shown in Fig. The
first character is sent as a packet by itself, but the next two characters are not sent, since the
connection has a small packet outstanding.
At time 600, when the ACK of the first packet is received, along with the echo of the first
character, these two characters are sent.

TCP_STDURG Socket Option


There are two possible interpretations about where TCP’s urgent pointer points.
By default, the urgent pointer points to the data byte following the byte sent with
MSG_OOB flag.
If this socket option is set nonzero, the urgent pointer will point to the data byte sent with
the MSG_OOB flag.
7. Elementary UDP sockets
There are some fundamental differences between applications written using TCP versus
UDP. UDP is a connectionless, unreliable, datagram protocol, quite unlike the connection-
oriented, reliable byte stream provided by TCP.
The client does not establish a connection with the server. Instead, the client just sends a
datagram to the server using the sendto function, which requires the address of the destination
(the server) as a parameter. Similarly, the server does not accept a connection from a client.
Instead, the server just calls the recvfrom function, which waits until data arrives from some
client. recvfrom returns the protocol address of the client, along with the datagram, so the server
can send a response to the correct client.
Figure: Socket functions for UDP client/server.

The above fig. shows a timeline of the typical scenario that takes place for a UDP
client/server exchange.
recvfrom and sendto function
These two functions are similar to the standard read and write functions, but three
additional arguments are required.
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags, struct sockaddr *from,
socklen_t *addrlen);
ssize_t sendto(int sockfd, const void *buff, size_t nbytes, int flags, const struct sockaddr
*to, socklen_t addrlen);
Both return: number of bytes read or written if OK, –1 on error
sockfd refers to an open socket descriptor.
buff is a pointer to buffer send from or read into.
nbytes number of bytes to read or write.
flags is either 0 or is formed by logically OR’ing one or more of the constants.
from points to the socket address structure filled by recvfrom function, with the protocol
address of who sent the data.
to points to socket address structure containing the protocol address of where the data is to
be sent.
addrlen contains the size of the socket address structure.
8. UDP Echo server
This program demonstrates a simple UDP server. It will receive one line of text; echo that
line back to the client and stops
Figure: Simple echo client/server using UDP.

#include "unp.h"
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr, cliaddr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
bind(sockfd, (SA *) &servaddr, sizeof(servaddr));
dg_echo(sockfd, (SA *) &cliaddr, sizeof(cliaddr));
}
Create UDP socket, bind server's well-known port
We create a UDP socket by specifying the second argument to socket as
SOCK_DGRAM. The function dg_echo is called to perform server processing.
UDP Echo Server: dg_echo Function
#include "unp.h"
void dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen)
{
int n;
socklen_t len;
char mesg[MAXLINE];
for ( ; ; )
{
len = clilen;
n = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);
sendto(sockfd, mesg, n, 0, pcliaddr, len);
}
}
Read datagram, echo back to sender
This function is a simple loop that reads the next datagram arriving at the server's port
using recvfrom and sends it back using sendto.
Difference between TCP and UDP
UDP function never terminates. Since UDP is a connectionless protocol, there is nothing
like an EOF as we have with TCP.
Most TCP servers are concurrent and most UDP servers are iterative.
Each UDP socket has a receive buffer and each datagram that arrives for this socket is
placed in that socket receive buffer. When the process calls recvfrom, the next datagram from the
buffer is returned to the process in a first-in, first-out (FIFO) order. This way, if multiple
datagrams arrive for the socket before the process can read what's already queued for the socket,
the arriving datagrams are just added to the socket receive buffer. But, this buffer has a limited
size.
Figure: Summary of TCP client/server with two clients.

There are two connected sockets and each of the two connected sockets on the server host has its
own socket receive buffer.
Figure: Summary of UDP client/server with two clients.

There is only one server process and it has a single socket on which it receives all
arriving datagrams and sends all responses. That socket has a receive buffer into which all
arriving datagrams are placed.
9. UDP echo client
#include "unp.h"
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if(argc != 2)
err_quit("usage: udpcli <IPaddress>");
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
dg_cli(stdin, sockfd, (SA *) &servaddr, sizeof(servaddr));
exit(0);
}
UDP Echo Client: dg_cli Function
#include "unp.h"
void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];
while (fgets(sendline, MAXLINE, fp) != NULL)
{
sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
recvline[n] = 0; /* null terminate */
fputs(recvline, stdout);
}
}
There are four steps in the client processing loop:
i. Read a line from standard input using fgets
ii. Send the line to the server using sendto
iii. Read back the server's echo using recvfrom
iv. Print the echoed line to standard output using fputs.
10. Multiplexing TCP and UDP sockets
We can combine the TCP echo server with the UDP echo server into a single server that
uses select to multiplex a TCP and UDP socket.
The code for the implementation of server that handles both TCP and UDP data is given
below.
#include “unp.h”
int main(int argc, char **argv)
{
int listenfd, connfd, udpfd, nready, maxfdp1;
pid_t childpid;
socketlen_t len;
char msg[MAXLINE];
ssize_t n;
fd_set rset;
const int on = 1;
struct sockaddr_in servaddr, cliaddr;
void sig_chld(int);
/* Create listening TCP Socket*/
listenfd=socket(AF_INET,SOCK_STREAM,0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(SERV_PORT);
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
bind(listenfd,(SA*)&servaddr,sizeof(servaddr));
listen(listenfd,LISTENQ);
/* Create UDP Socket*/
udpfd=socket(AF_INET,SOCK_DGRAM,0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(SERV_PORT);
bind(udpfd,(SA*)&servaddr,sizeof(servaddr));
/*establish signal handler for SIGCHLD*/
signal(SIGCHLD, sig_chld);
/*prepare for select*/
FD_ZERO(&rset);
maxfdp1 = max(listenfd,udpfd)+1;
for(; ;)
{
/*call select*/
FD_SET(listenfd,&rset);
FD_SET(udpfd,&rset);
if((nready=select(maxfdp1,&rset,NULL,NULL,NULL))<0);
if(errno==EINTR)
continue;
else
err_sys(“Select Error”);
}
/* handle new client connection*/
if(FD_ISSET(listedfd,&rset))
{
len = sizeof(cliaddr);
connfd = accept(listenfd, (SA*)&cliaddr,&len);
if((childpid=fork( ))==0)
{
close(listenfd);
str_echo(connfd);
exit(0);
}
close(connfd);
}
/* handle arrival of data*/
if(FD_ISSET(udpfd,&rset))
{
len = sizeof(cliaddr);
n=recvfrom(udpfd, msg, MAXLINE, 0, (SA*)&cliaddr, &len);
sendto(udpfd,msg,n,0,(SA*)&cliaddr,len);
}
}
}
Create listening TCP socket
A listening TCP socket is created that is bound to the server's well-known port. We set
the SO_REUSEADDR socket option in case connections exist on this port.
Create UDP socket
A UDP socket is also created and bound to the same port. Even though the same port is
used for TCP and UDP sockets, there is no need to set the SO_REUSEADDR socket option
before this call to bind, because TCP ports are independent of UDP ports.
Establish signal handler for SIGCHLD
A signal handler is established for SIGCHLD because TCP connections will be handled
by a child process.
Prepare for select
We initialize a descriptor set for select and calculate the maximum of the two descriptors
for which we will wait.
Call select
We call select, waiting only for readability on the listening TCP socket or readability on
the UDP socket. Since our sig_chld handler can interrupt our call to select, we handle an error of
EINTR.
Handle new client connection
We accept a new client connection when the listening TCP socket is readable, fork a
child, and call our str_echo function in the child.
Handle arrival of datagram
If the UDP socket is readable, a datagram has arrived. We read it with recvfrom and send
it back to the client with sendto.
11. Domain Name System
The DNS is used primarily to map between hostnames and IP addresses. A hostname can
be either a simple name, such as solaris or freebsd, or a fully qualified domain name '(FQDN),
such as solaris.unpbook.com.
Technically, an FQDN is also called an absolute name and must end with a period, but
users often omit the ending period.
The DNS is the service used to convert human readable names of hosts to IP addresses.
Host names are not case sensitive and can contain alphabetic or numeric letters or the hyphen.
Avoid the underscore. A FQDN consists of the host name plus domain name as in the following
example: computername.domain.com.
Resource Records
Entries in the DNS are known as resource records (RRs). There are only a few types of
RRs that we are interested in.
A - An A record maps a hostname into a 32-bit IPv4 address.
AAAA - A AAAA record, called a "quad A" record, maps a hostname into a 128-bit
IPv6 address. The term "quad A" was chosen because a 128-bit address is four times larger
than a 32-bit address.
PTR - PTR records (called "pointer records") map IP addresses into hostnames. For an
IPv4 address, then 4 bytes of the 32-bit address are reversed, each byte is converted to its
decimal ASCII value (0–255), and in-addr.arpa is the appended. The resulting string is used
in the PTR query.
MX An MX record specifies a host to act as a "mail exchanger" for the specified host.
CNAME CNAME stands for "canonical name." A common use is to assign CNAME
records for common services, such as ftp and www. If people use these service names
instead of the actual hostnames, it is transparent when a service is moved to another host.
Resolvers and Name Servers
Organizations run one or more name servers, often the program known as BIND
(Berkeley Internet Name Domain). Applications such as the clients and servers contact a DNS
server by calling functions in a library known as the resolver. The common resolver functions are
gethostbyname and gethostbyaddr. The former maps a hostname into its IPv4 addresses, and the
latter does the reverse mapping.
The below fig. shows a typical arrangement of applications, resolvers, and name servers.
We now write the application code. On some systems, the resolver code is contained in a system
library and is link-edited into the application when the application is built. On others, there is a
centralized resolver daemon that all applications share, and the system library code performs
RPCs to this daemon. In either case, application code calls the resolver code using normal
function calls, typically calling the functions gethostbyname and gethostbyaddr.
The resolver code reads its system-dependent configuration files to determine the
location of the organization's name servers.
Figure. Typical arrangement of clients, resolvers, and name servers.

The resolver sends the query to the local name server using UDP. If the local name server
does not know the answer, it will normally query other name servers across the Internet, also
using UDP. If the answers are too large to fit in a UDP packet, the resolver will automatically
switch to TCP.
12. gethostbyname function
Host computers are normally known by human-readable names. Most applications should
deal with names, not addresses.
The most basic function that looks up a hostname is gethostbyname. If successful, it returns a
pointer to a hostent structure that contains all the IPv4 addresses for the host. However, it is
limited in that it can only return IPv4 addresses.
#include <netdb.h>
struct hostent *gethostbyname (const char *hostname);
Returns: non-null pointer if OK,NULL on error with h_errno set
The non-null pointer returned by this function points to the following hostent structure:
struct hostent
{
char *h_name; /* official (canonical) name of host */
char **h_aliases; /* pointer to array of pointers to alias names */
int h_addrtype; /* host address type: AF_INET */
int h_length; /* length of address: 4 */
char **h_addr_list; /* ptr to array of ptrs with IPv4 addrs */
};
h_name points to the character string that contains the name of the host.
h_aliases is a pointer to a NULL terminated list of pointers, each of which points to a
character string that represents an alternative name for the host.
h_addrtype contains the address type of the host.
h_length contains the address length.
h_addr_list is a pointer to a NULL terminated list of pointers, each of which points to a
network address for the host, in network byte order.
In terms of the DNS, gethostbyname performs a query for an A record. This function can return
only IPv4 addresses.
The fig. shows the arrangement of the hostent structure and the information that it points
to assuming the hostname that is looked up has two alias names and three IPv4 addresses. Of
these fields, the official hostname and all the aliases are null-terminated C strings.
Figure . hostent structure and the information it contains.
13. IPv6 support in DNS
RES_USE_INET6 Resolver Option
We can use RES_USE_INET6 resolver that we want IPv6 address returned by
gethostbyname.
Three ways to set in
i. In the application program, add:
#include<resolv.h>
res.init();
res.option|=RES_USE_INET6;
ii. Set environment variable: export RES_OPTIONS = inet6
iii. Set options inet6 to be contained in the file.
#include<netdb.h>
struct hostent *gethostbyname2*(const char *hostname, int family);
Argument
const char *hostname: host name.
int family: AF_INET 0R AF_INET6
RES_USE_INET6 Option Off (gethostbyname)
Search for A records. If found, return IPv4 address (h_length=4). Else error
This provides backward compatibility or all existing IPv4 application.
RES_USE_INET6 ON (gethostbyname)
Search for AAAA records. If found, return IPv6 address (h_length=16).
Else search for A records. If found, return IPv4 mapped IPv6 address. Else error.
RES_USE_INET6 Option OFF (gethostbyname2)
gethostbyname2 (host, AF_INET): Search for A records, If found, return IPv4 addresses.
Else error.
gethostbyname2 (host, AF_INET6): Search for AAAA records, If found, return IPv6
addresses. Else error.
RES_USE_INET6 Option ON (gethostbyname2)
gethostbyname2 (host, AF_INET): Search for A records, If found, return IPv4 mapped
IPv6 addresses (h_length=16). Else error.
gethostbyname2 (host, AF_INET6): Search for AAAA records, If found, return IPv6
addresses (h_length=16). Else error.
14. gethostbyaddr function
getservbyport function
The function gethostbyaddr takes a binary IPv4 address and tries to find the hostname
corresponding to that address. This is the reverse of gethostbyname.
#include <netdb.h>
struct hostent *gethostbyaddr (const char *addr, socklen_t len, int family);
Returns: non-null pointer if OK, NULL on error with h_errno set
This function returns a pointer to the hostent structure. The field of interest in this
structure is normally h_name, the canonical hostname.
The addr argument is not a char*, but is really a pointer to an in_addr structure containing the
IPv4 address. len is the size of this structure. The family argument is AF_INET.
15. getservbyname and getservbyport function.
The getservbyname( ) function searches the database and finds an entry which matches
the specified service name and the specified protocol, opening a connection to the database if
necessary.
#include <netdb.h>
struct servent *getservbyname (const char *servname, const char *protoname);
Returns: non-null pointer if OK, NULL on error
servname
The pointer to the character string that contains the name of the service for which
information is to be retrieved ( for example, telnet).
protoname
The pointer to the character string that contains the name of the protocol that further
qualifies the search criteria. For example, if the servname is telnet, and the protoname is tcp,
then the call will return the telnet server that uses the TCP protocol.
This function returns a pointer to the following structure: The structure struct servent is
defined in <netdb>
.struct servent
{
char *s_name; /* official service name */
char **s_aliases; /* alias list */
int s-port; /* port number, network-byte order */
char *s_proto; /* protocol to use */
};
s_name points to the character string that contains the name of the service.
s_aliases is a pointer to a NULL terminated array of alternate names for the service.
s_port is the port number assigned to the service
s_proto is the protocol being used by the service.
getservbyport function
The getservbyport( ) function searches the database and finds an entry which matches
the specified port number and the specified protocol, opening a connection to the database if
necessary.
#include <netdb.h>
struct servent *getservbyport (int port, const char *protoname);
Returns: non-null pointer if OK, NULL on error
port
The port number for which service information is to be retrieved.
protoname
The pointer to the character string that contains the name of the protocol that further
qualifies the search criteria. For example, if port is 10, and the protoname is tcp, then call will
return the server that uses the TCP protocol on port number 10.
The structure struct servent is defined in <netdb>
struct servent
{
char *s_name; /* official service name */
char **s_aliases; /* alias list */
int s-port; /* port number, network-byte order */
char *s_proto; /* protocol to use */
};
s_name points to the character string that contains the name of the service.
s_aliases is a pointer to a NULL terminated array of alternate names for the service.
s_port is the port number assigned to the service
s_proto is the protocol being used by the service.
PART A
1. What is the use of getsockopt function?
The getsockopt function is used to get the values of socket options that were set already.
The prototype of getsockopt as follows.
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
sockfd must refer to an open socket descriptor.
level indicates whether the socket options is generic or protocol-specific.
optval is a pointer to a variable into which the current value of the option is stored by
getsockopt( ).
optlen is the size of optval.
2. What is the use of setsockopt function?
The setsockopt function is used to set the values for the socket options. The prototype of
setsockopt is as follows:
int setsockopt(int sockfd, int level, int optname, const void *optval socklen_t optlen);
sockfd must refer to an open socket descriptor.
level indicates whether the socket options is generic or protocol-specific.
optval is a pointer to a variable from which the new value of the option is fetched by
setsockopt.
optlen is the size of optval.
3. What is pending error?
When an error occurs on a socket, the kernel sets a variable named SO_ERROR to one of
standard values. This is called the pending error.
4. What are the three scenarios resulted from SO_KEEPALIVE socket option?
i. The peer responds with the expected ACK.
ii. The peer responds with an RST
iii. There is no response from the peer to the keepalive signal.
5. What is half open connection?
If the client host crashes, the server process will never know about it. The server will
continually wait for input that can never arrive. This is called a half open connection.
6. What is an application ACK?
An application level acknowledgement is used to know that the peer application has read
our data. It is guaranteed that when the read in the client returns, the server process has read
the data we sent.
7. State the difference between TCP and UDP.
TCP UDP
Connection oriented Connection less
Reliable Unreliable
Byte stream oriented Datagram oriented

8. Mention the function calls used with UDP client.


i. socket( )
ii. sendto ( )
iii. recvfrom( )
iv. close( )
9. Mention the function calls used with UDP server.
i. socket( )
ii. bind ( )
iii. recvfrom( )
iv. sendto( )
10. List the steps involved in creating a UDP Echo server.
The steps to create a UDP server as follows:
i. Create a UDP socket
ii. Bind server’s well known port
iii. Read datagram
iv. Echo back to sender
11. List the steps involved in creating a UDP Echo client.
i. Create a UDP socket.
ii. Read a line from standard input using fgets
iii. Send the line to the server using sendto
iv. Read back the server’s echo using recvfrom
v. Print the echoed line to standard output using fputs.
12. What is the use of sendto function?
The sendto function is used by UDP to send a datagram packet to its peer. The function
usage is as follows.
13. What is the use of recvfrom function?
The recvfrom function is used by UDP to receive a datagram packet from its peer. The
function usage is as follows.
14. Distinguish between Connected UDP socket and Unconnected UDP socket.
Sl. No Unconnected UDP socket Connected UDP socket

1. Default UDP socket created when we Created as results of calling connect on a


create a socket in UDP. UDP socket.
2. We use sendto function to send any We use write or send function to send
data. data.
3. We use recvfrom to receive data. We use read to read data.
We should specify destination IP No need to specify.
4. address and port number for the above
function.
5. Asynchronous errors are not returned in Asynchronous errors are returned to the
UDP sockets. process.

15. How the two datagrams sent on the unconnected UDP socket?
i. Connect the socket
ii. Output the first datagram
iii. Unconnect the socket
iv. Connect the socket
v. Output the second datagram
vi. Unconnect the socket.
16. How the two datagrams sent on the connected UDP socket?
i. Connect the socket
ii. Output the first datagram
iii. Output the second datagram
17. List the steps involved in multiplexing TCP and UDP echo server using select.
i. Create listening TCP socket
ii. Create UDP socket
iii. Establish signal handler for SIGCHLD
iv. Call select
v. Handle arrival of datagram
18. What is Domain Name System?
The Domain Name System, or DNS, is used to map between host names and IP
addresses. A host name can either be a simple name, or a FQDN(Fully Qualified Domain
Name).
19. What is the use of gethostbyname function?
The gethostbyname is a resolver function used to map a host name into its IP address.
20. What is the use of gethostbyaddr function?
The gethostbyaddr is a resolver function used to map a IP address into a host name.
21. What is a name server?
A name server is a program called BIND (Berkeley Internet Name Domain) which
contains the mappings for names to numeric addresses.
22. What is the function of gethostbyname ( )? [Jun 2007]
Host computers are normally known by human readable names. Most applications should
deal with names not addresses.
The most basic function that look up a host name is gethostbyname( ).
If successful, it returns a pointer to a hostent structure that contains all the IPv4 addresses
for the host.
23. Write about IP Socket Options. [Dec 07]
In addition to binding a socket to a local address or connecting it to a destination address,
application programs need a method to control the socket. Such IP socket options are
IP_HDRINCL: If this option is set for a raw IP socket.
IP_OPTIONS: sets or get the IP options to be sent with every packet from this socket.
IP_TTL: set or retrieve the current time to live field that is sending in every packet send
from this socket.
PART B
1. Write a socket program to implement UDP echo client/ server application?
Fig: simple UDP echo client and server
Client-read the i/p from standard i/p and writes to the server, read line from the server
and prints it on its standard output.
Server-read the line from the network and echoes it to the client
UDP-echo server program
dg_echo fuction
UDP _Echo client program
dg_cli function
2. What is meant by generic socket option? Explain in detail.
Definition
Level_SOL_SOCKET
SO_BROADCAST, SO_DEBUG, SO_DONTROUTE, SO_ERROR,
SO_KEEPALIVE,SO_RCVBUF,SO_SNDBUF,SO_OOBLINE,SO_RCVLOWAT,
SO_SNDLOWAT,SO_RCVTIMEO,SO_SNDTIMEO,SO_REUSEADDR,SO_REU
SEPORT
3. IP socket option
IP socket options-level IPPROTO_IP
IP_HDRINCL
IP_OPTIONS
IP_RECVDSTADDR
IP_RECVIF
IP_TOS
IP_TTL
4. TCP socket options
TCP_KEEPALIVE
TCP_MAXRT
TCP_MAXSEG
TCP_NODELAY
TCP_STDURG
4. Write a program to display the port number from a given service name.
Syntax for getservbyname
Program using getservbyname
5. Write a program to find the IP address from a given host name?
Syntax for gethostbyname
Program using gethostbyname
6. Elementary UDP sockets.
Fig: UDP socket function
Description and syntax of various system calls
Socket(),bind(), recvfrom(), sendto(),close()
7. Domain Name system
DNS is used to map between hostname and IP addresses.
Components of DNS
Resolver, Name server, Database of resource records
Functions of Domain Name system
Fig:Resolver and Name servers
DNS alternatives
gethostbyname and gethostbyaddr function
struct hostent *gethostbyname(const char *hostname)
struct hostent *gethostbyaddr(const char *addr, socklen_t len, int family);
getservbyname and getservbyport function
struct servent *getservbyname(const char *servname,const char
*protoname)
struct servent *getservbyport(int port,const char *protoname)

You might also like