aboutsummaryrefslogtreecommitdiffstats
path: root/ipv6-connect.c
blob: 2da1edb7256bd32f861a1a3cbf4da0ebc4c1cc36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/*
%%% copyright-cmetz-97
This software is Copyright 1997-1998 by Craig Metz, All Rights Reserved.
The Inner Net License Version 2 applies to this software.
You should have received a copy of the license with this software. If
you didn't get a copy, you may request one from <license@inner.net>.

*/


#include "config.h"
#ifdef INET6_ENABLE
#include <sys/types.h>
#include <stdio.h>
#ifdef HAVE_NET_SOCKET_H
#include <net/socket.h>
#else
#include <sys/socket.h>
#endif
#include <netinet/in.h>
#include <errno.h>
#include <netdb.h>
#include <signal.h>

/* This patch, supplying SA_LEN if it's undefined, is from Red Hat */
#ifndef SA_LEN
#define SA_LEN(sa)	sa_len(sa)

static size_t sa_len(struct sockaddr *sa)
{
	switch(sa->sa_family) {
#if defined(AF_INET)
		case AF_INET:
			return sizeof(struct sockaddr_in);
#endif
#if defined(AF_INET6) && defined(INET6_ENABLE)
		case AF_INET6:
			return sizeof(struct sockaddr_in6);
#endif
		default:
			return sizeof(struct sockaddr);
	}
}
#endif /* SA_LEN */

static int default_trying_callback(struct sockaddr *sa)
{
  char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];

  if (getnameinfo(sa, SA_LEN(sa), hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
    fprintf(stderr, "inner_getstream: getnameinfo failed\n");
    return -1;
  };

  fprintf(stderr, "Trying %s.%s...\n", hbuf, sbuf);
  return 0;
};

static int default_error_callback(char *myname, char *message)
{
  fprintf(stderr, "%s: %s\n", myname, message);
  return 0;
};

int inner_connect(struct addrinfo *ai, void *request, int requestlen, int (*trying_callback)(struct sockaddr *sa), int (*error_callback)(char *myname, char *message), char *myname, struct addrinfo **pai)
{
  int fd;
  char errorbuf[128];

  if (!trying_callback)
    trying_callback = default_trying_callback;

  if (!error_callback)
    error_callback = default_error_callback;

  for (; ai; ai = ai->ai_next) {
    if (trying_callback(ai->ai_addr))
      continue;

    if ((fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) {
      snprintf(errorbuf, sizeof(errorbuf), "socket: %s(%d)", strerror(errno), errno);
      error_callback(myname, errorbuf);
      continue;
    };

    if (connect(fd, ai->ai_addr, ai->ai_addrlen) < 0) {
      snprintf(errorbuf, sizeof(errorbuf), "connect: %s(%d)", strerror(errno), errno);
      error_callback(myname, errorbuf);
      close(fd);	/* just after a connect; no reads or writes yet */
      continue;
    }
    break;
  };

  if (ai) {
    if (pai)
      *pai = ai;
  } else {
    snprintf(errorbuf, sizeof(errorbuf), "no connections result");
    error_callback(myname, errorbuf);
    fd = -1;
  };

  return fd;
};

#endif /* INET6_ENABLE */