Writing a Multihomed Server (Perl Cookbook, 2nd Edition)

## 17.16. Writing a Multihomed Server

### 17.16.1. Problem

You want to write a server that knows that the machine it runs on has multiple IP addresses, and that it should possibly do different things for each address.

### 17.16.2. Solution

Don't bind your server to a particular address. Instead, bind to `INADDR_ANY`. Then once you've `accept` ed a connection, use `getsockname` on the client socket to find out which address the client connected to:

>     use Socket;

>     socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
>     setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1);
>     bind(SERVER, sockaddr_in($server_port, INADDR_ANY))
>         or die "Binding: $!\n";

>     # accept loop
>     while (accept(CLIENT, SERVER)) {
>         $my_socket_address = getsockname(CLIENT);
>         ($port, $myaddr)   = sockaddr_in($my_socket_address);
>     }

### 17.16.3. Discussion

Whereas `getpeername` (as discussed in Recipe 17.7) returns the address of the remote end of the socket, `getsockname` returns the address of the local end. When we've bound to `INADDR_ANY`, thus accepting connections on any address the machine has, we need to use `getsockname` to identify which address the client connected to.

If you're using IO::Socket::INET, your code will look like this:

>     $server = IO::Socket::INET->new(LocalPort => $server_port,
>                                     Type      => SOCK_STREAM,
>                                     Proto     => 'tcp',
>                                     Listen    => 10)
>         or die "Can't create server socket: $@\n";

>     while ($client = $server->accept( )) {
>         $my_socket_address = $client->sockname( );
>         ($port, $myaddr)   = sockaddr_in($my_socket_address);
>         # ...
>     }

If you don't specify a local port to `IO::Socket::INET->new`, your socket will be bound to `INADDR_ANY`.

If you want your server to listen only for a particular virtual host, don't use `INADDR_ANY`. Instead, bind to a specific host address:

>     use Socket;

>     $port = 4269;                       # port to bind to
>     $host = "specific.host.com";        # virtual host to listen on

>     socket(Server, PF_INET, SOCK_STREAM, getprotobyname("tcp"))
>         or die "socket: $!";
>     bind(Server, sockaddr_in($port, inet_aton($host)))
>         or die "bind: $!";
>     while ($client_address = accept(Client, Server)) {
>         # ...
>     }

### 17.16.4. See Also

The `getsockname` function in Chapter 29 of Programming Perl and in perlfunc(1); the documentation for the standard Socket and IO::Socket modules; the section on "Sockets" in Chapter 16 of Programming Perl or perlipc(1)

Copyright © 2003 O'Reilly & Associates. All rights reserved.