[Gllug] listening on IP interfaces

Simon A. Boggis simon at dcs.qmul.ac.uk
Thu Sep 25 19:45:47 UTC 2003


On Thu, 2003-09-25 at 17:25, Tethys wrote:
> 
> "t.clarke" writes:
> 
> >I know you can set up a process to listen on a tcp socket by either a
> >specific IP address or the * wildcard address,  but does anyone know if it is
> >possible (and how you do it) to listen to two sepcific interface addresses
> >(in this case I want to listen on a 192.168 address and the 127.0.0.1 loopback
> >address)  ??
> 
> Create two sockets, bind them to the approrpiate addresses, and listen
> on both? Or am I missing something?
> 
> Tet

As Tet says, instead of binding INADDR_ANY (0.0.0.0) bind the specific
address you are interested in. If you are interested in more than one,
you'll have to bind each and then select() on the bound sockets to find
out when one needs servicing.

Note that 0.0.0.0 will match any address your machine has _regardless_
of interface. This is a frequent gotcha - just because you bind the
address of a particular interface doesn't mean that the packets are
coming in on that interface. You can use the SO_BINDTODEVICE socket
option (see man (7) socket) to force this behaviour, but it is very much
not portable.

If you bind 127.0.0.1 you will only get connections from local clients
(although those clients can specify the address of an interface, not
necessarily 127.0.0.1, to get there).

If you bind a specific IP address of an interface you'll only get
connections directed to that address.

Below is a crufty example server in C. Takes one argument, numeric IP
address to bind.

If you try running it bound to 0.0.0.0 (default), 127.0.0.1, and
your-ip-address, and connect to it as:

local
  telnet 127.0.0.1 4321
  telnet your-ip-address

remote
  telnet your-ip-address

you'll see the effects... which are probably clearer than my
explanation.

Have fun, 

Simon

---- cut here ----
#include <stdlib.h>
#include <stdio.h>

#include <string.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/socket.h>

#include <unistd.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <sys/types.h>
#include <sys/wait.h>

#include <signal.h>

#define PORT 4321
#define BUFLEN 4096

int main(int argc, char *argv[]) {
  struct sockaddr_in addr;
  int sock;
  int flag=1;

  switch(argc) {
    case 1:
      addr.sin_addr.s_addr = INADDR_ANY;
      break;
    case 2:
      if (!inet_aton(argv[1],&(addr.sin_addr))) {
	perror("bad IP address");
	exit(1);
      }
      break;
    default:
      fprintf(stderr,"Usage: %s [IP address to bind, default 0.0.0.0]\n",
	      argv[0]);
      exit(1);
  }

  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("socket");
    exit(1);
  }

  /* set socket options like SO_REUSEADDR or SO_BROADCAST if required */
  if((setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag))) < 0) {
    perror("setsockopt");
    exit(1);
  }

  addr.sin_family = AF_INET; /* host byte order */
  addr.sin_port = htons(PORT); /* short, network byte order */
  memset(&(addr.sin_zero), 0, 8); /* zero the rest of the struct */

  if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr))==-1) {
    perror("bind");
    exit(1);
  }

  if (listen(sock, 5) == -1) {
     perror("listen");
     exit(1);
  }

  signal(SIGPIPE,SIG_IGN);
  signal(SIGCHLD,SIG_IGN);

  printf("server: listening on %s:%d\n", inet_ntoa(addr.sin_addr), PORT);

  while(1) {  /* accept() loop */
    int fd;
    struct sockaddr_in cli_addr;
    int len;
    char buf[BUFLEN];
    int sin_size = sizeof(struct sockaddr_in);
    pid_t pid;

    if ((fd = accept(sock, (struct sockaddr *)&cli_addr,&sin_size))==-1) {
      perror("accept");
      continue;
    }

    printf("server: got connection from %s\n", inet_ntoa(cli_addr.sin_addr));

    pid = fork();

    switch(pid) {
    case -1:
      perror("fork");
      exit(0);
    case 0: /* child */
      if (send(fd, "Hello, world!\n", 14, 0) == -1)
        perror("send");
      close(fd);
      _exit(0);
    default: /* parent */
      do {
	memset(buf,'\0',BUFLEN);
	len = recv(fd, buf, BUFLEN-1, 0);
	if (len<0) {
	  perror("recv");
	}
	printf("read %d bytes '%s'\n", len, (len>0)?buf:"");
      } while (len>0 && strncasecmp(buf,"quit",4)!=0 && buf[0]!=0x4); /* ctrl-d */
      printf("client disconnected\n");
      close(fd); 
    }
    while(waitpid(-1,NULL,WNOHANG) > 0); /* clean up child processes */
  }

  close(sock);

  exit(0);
} 
---- cut here ----

-- 
----------------------------------------------------------------------
Dr Simon A. Boggis                                  Systems Programmer
Department of Computer Science,                     Tel. 020 7882 7522
Queen Mary, University of London, London E1 4NS UK. 
---- GPG public key <http://www.dcs.qmul.ac.uk/~simon/#publickey> ----


-- 
Gllug mailing list  -  Gllug at linux.co.uk
http://list.ftech.net/mailman/listinfo/gllug




More information about the GLLUG mailing list