4.10 getsockname and
getpeername Functions
These two functions return either the local
protocol address associated with a socket (getsockname) or
the foreign protocol address associated with a socket
(getpeername).
#include <sys/socket.h>
|
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
|
int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);
|
Both return: 0 if OK, -1 on error
|
Notice that the final argument for both
functions is a value-result argument. That is, both functions fill
in the socket address structure pointed to by localaddr or peeraddr.
We mentioned in our discussion of bind
that the term "name" is misleading. These two functions return the
protocol address associated with one of the two ends of a network
connection, which for IPV4 and IPV6 is the combination of an IP
address and port number. These functions have nothing to do with
domain names (Chapter 11).
These two functions are required for the
following reasons:
-
After connect successfully returns in a
TCP client that does not call bind, getsockname
returns the local IP address and local port number assigned to the
connection by the kernel.
-
After calling bind with a port number
of 0 (telling the kernel to choose the local port number),
getsockname returns the local port number that was
assigned.
-
getsockname can be called to obtain the
address family of a socket, as we show in Figure 4.19.
-
In a TCP server that binds the wildcard
IP address (Figure 1.9), once a
connection is established with a client (accept returns
successfully), the server can call getsockname to obtain
the local IP address assigned to the connection. The socket
descriptor argument in this call must be that of the connected
socket, and not the listening socket.
-
When a server is execed by the process
that calls accept, the only way the server can obtain the
identity of the client is to call getpeername. This is
what happens whenever inetd (Section 13.5)
forks and execs a TCP server. Figure 4.18 shows this scenario.
inetd calls accept (top left box) and two values
are returned: the connected socket descriptor, connfd, is
the return value of the function, and the small box we label
"peer's address" (an Internet socket address structure) contains
the IP address and port number of the client. fork is
called and a child of inetd is created. Since the child
starts with a copy of the parent's memory image, the socket address
structure is available to the child, as is the connected socket
descriptor (since the descriptors are shared between the parent and
child). But when the child execs the real server (say the
Telnet server that we show), the memory image of the child is
replaced with the new program file for the Telnet server (i.e., the
socket address structure containing the peer's address is lost),
and the connected socket descriptor remains open across the
exec. One of the first function calls performed by the
Telnet server is getpeername to obtain the IP address and
port number of the client.
Obviously the Telnet server in this final
example must know the value of connfd when it starts.
There are two common ways to do this. First, the process calling
exec can format the descriptor number as a character
string and pass it as a command-line argument to the newly
execed program. Alternately, a convention can be
established that a certain descriptor is always set to the
connected socket before calling exec. The latter is what
inetd does, always setting descriptors 0, 1, and 2 to be
the connected socket.
Example: Obtaining the Address Family
of a Socket
The sockfd_to_family function shown in
Figure 4.19 returns the
address family of a socket.
Figure 4.19
Return the address family of a socket.
lib/sockfd_to_family.c
1 #include "unp.h"
2 int
3 sockfd_to_family(int sockfd)
4 {
5 struct sockaddr_storage ss;
6 socklen_t len;
7 len = sizeof(ss);
8 if (getsockname(sockfd, (SA *) &ss, &len) < 0)
9 return (-1);
10 return (ss.ss_family);
11 }
Allocate room for largest socket
address structure
5
Since we do not know what type of socket address structure to
allocate, we use a sockaddr_storage value, since it can
hold any socket address structure supported by the system.
Call getsockname
7鈥?0
We call getsockname and return the address family.
Since the POSIX specification allows a call to
getsockname on an unbound socket, this function should
work for any open socket descriptor.
|