]> Pileus Git - ~andy/fetchmail/blob - ipv6-connect.c
_( -> GT_(
[~andy/fetchmail] / ipv6-connect.c
1 /*
2 %%% copyright-cmetz-97
3 This software is Copyright 1997-1998 by Craig Metz, All Rights Reserved.
4 The Inner Net License Version 2 applies to this software.
5 You should have received a copy of the license with this software. If
6 you didn't get a copy, you may request one from <license@inner.net>.
7
8 */
9
10
11 #include "config.h"
12 #ifdef INET6_ENABLE
13 #include <sys/types.h>
14 #include <stdio.h>
15 #ifdef HAVE_NET_SOCKET_H
16 #include <net/socket.h>
17 #else
18 #include <sys/socket.h>
19 #endif
20 #include <netinet/in.h>
21 #include <errno.h>
22 #include <netdb.h>
23 #include <signal.h>
24
25 /* This patch, supplying SA_LEN if it's undefined, is from Red Hat */
26 #ifndef SA_LEN
27 #define SA_LEN(sa)      sa_len(sa)
28
29 static size_t sa_len(struct sockaddr *sa)
30 {
31         switch(sa->sa_family) {
32 #if defined(AF_INET)
33                 case AF_INET:
34                         return sizeof(struct sockaddr_in);
35 #endif
36 #if defined(AF_INET6) && defined(INET6_ENABLE)
37                 case AF_INET6:
38                         return sizeof(struct sockaddr_in6);
39 #endif
40                 default:
41                         return sizeof(struct sockaddr);
42         }
43 }
44 #endif /* SA_LEN */
45
46 static int default_trying_callback(struct sockaddr *sa)
47 {
48   char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
49
50   if (getnameinfo(sa, SA_LEN(sa), hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
51     fprintf(stderr, "inner_getstream: getnameinfo failed\n");
52     return -1;
53   };
54
55   fprintf(stderr, "Trying %s.%s...\n", hbuf, sbuf);
56   return 0;
57 };
58
59 static int default_error_callback(char *myname, char *message)
60 {
61   fprintf(stderr, "%s: %s\n", myname, message);
62   return 0;
63 };
64
65 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)
66 {
67   int fd;
68   char errorbuf[128];
69
70   if (!trying_callback)
71     trying_callback = default_trying_callback;
72
73   if (!error_callback)
74     error_callback = default_error_callback;
75
76   for (; ai; ai = ai->ai_next) {
77     if (trying_callback(ai->ai_addr))
78       continue;
79
80     if ((fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) {
81 #ifdef HAVE_SNPRINTF
82      snprintf(errorbuf, sizeof(errorbuf),
83 #else
84      sprintf(errorbuf,
85 #endif
86         "socket: %s(%d)", strerror(errno), errno);
87       error_callback(myname, errorbuf);
88       continue;
89     };
90
91     if (connect(fd, ai->ai_addr, ai->ai_addrlen) < 0) {
92 #ifdef HAVE_SNPRINTF
93      snprintf(errorbuf, sizeof(errorbuf),
94 #else
95      sprintf(errorbuf,
96 #endif
97          "connect: %s(%d)", strerror(errno), errno);
98       error_callback(myname, errorbuf);
99       close(fd);        /* just after a connect; no reads or writes yet */
100       continue;
101     }
102     break;
103   };
104
105   if (ai) {
106     if (pai)
107       *pai = ai;
108   } else {
109 #ifdef HAVE_SNPRINTF
110      snprintf(errorbuf, sizeof(errorbuf),
111 #else
112      sprintf(errorbuf,
113 #endif
114        "no connections result");
115     error_callback(myname, errorbuf);
116     fd = -1;
117   };
118
119   return fd;
120 };
121
122 #endif /* INET6_ENABLE */