#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>

int main __P((int, char **));

int
main(argc, argv)
     int argc;
     char **argv;
{
  struct servent *sp;
  unsigned long lport;
  u_int16_t port;
  char *ep;
  struct sockaddr_in6 serv;
  int servlen;
  struct sockaddr_in6 from;
  socklen_t fromlen;
  int s;
  int ls;
  char hbuf[INET6_ADDRSTRLEN];

  if (argc != 2) {
    fprintf(stderr, "usage: %s port\n",argv[0]);
    exit(1);
    /*NOTREACHED*/
  }
  sp = getservbyname(argv[1], "tcp");
  if (sp)
    port = sp->s_port & 0xffff;
  else {
    ep =NULL;
    errno = 0;
    lport =strtoul(argv[1], &ep, 10);
    if (!*argv[1] || errno || !ep || *ep) {
      fprintf(stderr, "%s: no such service\n", argv[1]);
      exit(1);
      /*NOTREACHED*/
    }
    if (lport & ~0xffff) {
      fprintf(stderr, "%s: out of range\n", argv[1]);
      exit(1);
      /*NOTREACHED*/
    }

    port = htons(lport & 0xffff);
  }
  endservent();

  memset(&serv, 0, sizeof(serv));
  serv.sin6_family = AF_INET6;
  /* linux/Solarisでは以下の行は不要 */
  serv.sin6_len = sizeof(struct sockaddr_in6);
  serv.sin6_port = port;
  servlen = sizeof(struct sockaddr_in6);

  s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
  if (s < 0) {
    perror("socket");
    exit(1);
    /*NOTREACHED*/
  }

  if (bind(s, (struct sockaddr *)&serv, servlen) < 0) {
    perror("bind");
    exit(1);
    /*NOTREACHED*/
  }
  if (listen(s, 5) < 0) {
    perror("listen");
    exit(1);
    /*NOTREACHED*/
  }

  while (1) {
    fromlen = sizeof(from);
    ls = accept(s, (struct sockaddr *)&from, &fromlen);
    if (ls < 0)
      continue;
    if (from.sin6_family != AF_INET6 || fromlen != sizeof(struct sockaddr_in6)) {
      exit(1);
      /*NOTREACHED*/
    }

    if (inet_ntop(AF_INET6, &from.sin6_addr, hbuf, sizeof(hbuf)) == NULL) {
      exit(1);
      /*NOTREACHED*/
    }
    write(ls, "Hello ",6);
    write(ls, hbuf, strlen(hbuf));
    write(ls, "\n", 1);
    close(ls);
  }
  /*NOTREACHED*/
}