Postfix3.3.1
inet_connect.c
[詳解]
1 /*++
2 /* NAME
3 /* inet_connect 3
4 /* SUMMARY
5 /* connect to TCP listener
6 /* SYNOPSIS
7 /* #include <connect.h>
8 /*
9 /* int inet_windowsize;
10 /*
11 /* int inet_connect(addr, block_mode, timeout)
12 /* const char *addr;
13 /* int block_mode;
14 /* int timeout;
15 /* DESCRIPTION
16 /* inet_connect connects to a TCP listener at
17 /* the specified address, and returns the resulting file descriptor.
18 /*
19 /* Specify an inet_windowsize value > 0 to override the TCP
20 /* window size that the client advertises to the server.
21 /*
22 /* Arguments:
23 /* .IP addr
24 /* The destination to connect to. The format is host:port. If no
25 /* host is specified, a port on the local host is assumed.
26 /* Host and port information may be given in numerical form
27 /* or as symbolical names.
28 /* .IP block_mode
29 /* Either NON_BLOCKING for a non-blocking socket, or BLOCKING for
30 /* blocking mode.
31 /* .IP timeout
32 /* Bounds the number of seconds that the operation may take. Specify
33 /* a value <= 0 to disable the time limit.
34 /* DIAGNOSTICS
35 /* The result is -1 when the connection could not be made.
36 /* The nature of the error is available via the global \fIerrno\fR
37 /* variable.
38 /* Fatal errors: other system call failures.
39 /* LICENSE
40 /* .ad
41 /* .fi
42 /* The Secure Mailer license must be distributed with this software.
43 /* AUTHOR(S)
44 /* Wietse Venema
45 /* IBM T.J. Watson Research
46 /* P.O. Box 704
47 /* Yorktown Heights, NY 10598, USA
48 /*--*/
49 
50 /* System interfaces. */
51 
52 #include <sys_defs.h>
53 #include <sys/socket.h>
54 #include <netinet/in.h>
55 #include <string.h>
56 #include <unistd.h>
57 #include <errno.h>
58 #include <netdb.h>
59 
60 /* Utility library. */
61 
62 #include "mymalloc.h"
63 #include "msg.h"
64 #include "iostuff.h"
65 #include "host_port.h"
66 #include "sane_connect.h"
67 #include "connect.h"
68 #include "timed_connect.h"
69 #include "myaddrinfo.h"
70 #include "sock_addr.h"
71 #include "inet_proto.h"
72 
73 static int inet_connect_one(struct addrinfo *, int, int);
74 
75 /* inet_connect - connect to TCP listener */
76 
77 int inet_connect(const char *addr, int block_mode, int timeout)
78 {
79  char *buf;
80  char *host;
81  char *port;
82  const char *parse_err;
83  struct addrinfo *res;
84  struct addrinfo *res0;
85  int aierr;
86  int sock;
87  MAI_HOSTADDR_STR hostaddr;
88  INET_PROTO_INFO *proto_info;
89  int found;
90 
91  /*
92  * Translate address information to internal form. No host defaults to
93  * the local host.
94  */
95  buf = mystrdup(addr);
96  if ((parse_err = host_port(buf, &host, "localhost", &port, (char *) 0)) != 0)
97  msg_fatal("%s: %s", addr, parse_err);
98  if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res0)) != 0)
99  msg_fatal("host/service %s/%s not found: %s",
100  host, port, MAI_STRERROR(aierr));
101  myfree(buf);
102 
103  proto_info = inet_proto_info();
104  for (sock = -1, found = 0, res = res0; res != 0; res = res->ai_next) {
105 
106  /*
107  * Safety net.
108  */
109  if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
110  msg_info("skipping address family %d for host %s",
111  res->ai_family, host);
112  continue;
113  }
114  found++;
115 
116  /*
117  * In case of multiple addresses, show what address we're trying now.
118  */
119  if (msg_verbose) {
120  SOCKADDR_TO_HOSTADDR(res->ai_addr, res->ai_addrlen,
121  &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
122  msg_info("trying... [%s]", hostaddr.buf);
123  }
124  if ((sock = inet_connect_one(res, block_mode, timeout)) < 0) {
125  if (msg_verbose)
126  msg_info("%m");
127  } else
128  break;
129  }
130  if (found == 0)
131  msg_fatal("host not found: %s", addr);
132  freeaddrinfo(res0);
133  return (sock);
134 }
135 
136 /* inet_connect_one - try to connect to one address */
137 
138 static int inet_connect_one(struct addrinfo * res, int block_mode, int timeout)
139 {
140  int sock;
141 
142  /*
143  * Create a client socket.
144  */
145  sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
146  if (sock < 0)
147  return (-1);
148 
149  /*
150  * Window scaling workaround.
151  */
152  if (inet_windowsize > 0)
154 
155  /*
156  * Timed connect.
157  */
158  if (timeout > 0) {
159  non_blocking(sock, NON_BLOCKING);
160  if (timed_connect(sock, res->ai_addr, res->ai_addrlen, timeout) < 0) {
161  close(sock);
162  return (-1);
163  }
164  if (block_mode != NON_BLOCKING)
165  non_blocking(sock, block_mode);
166  return (sock);
167  }
168 
169  /*
170  * Maybe block until connected.
171  */
172  else {
173  non_blocking(sock, block_mode);
174  if (sane_connect(sock, res->ai_addr, res->ai_addrlen) < 0
175  && errno != EINPROGRESS) {
176  close(sock);
177  return (-1);
178  }
179  return (sock);
180  }
181 }
int msg_verbose
Definition: msg.c:177
void myfree(void *ptr)
Definition: mymalloc.c:207
void freeaddrinfo(struct addrinfo *ai)
Definition: myaddrinfo.c:742
char * mystrdup(const char *str)
Definition: mymalloc.c:225
int sane_connect(int sock, struct sockaddr *sa, SOCKADDR_SIZE len)
Definition: sane_connect.c:44
#define inet_proto_info()
Definition: inet_proto.h:29
#define hostname_to_sockaddr(host, serv, sock, res)
Definition: myaddrinfo.h:171
#define SOCKADDR_TO_HOSTADDR(sa, salen, host, port, sock)
Definition: myaddrinfo.h:197
void set_inet_windowsize(int sock, int windowsize)
char buf[MAI_HOSTADDR_STRSIZE]
Definition: myaddrinfo.h:146
int timed_connect(int sock, struct sockaddr *sa, int len, int timeout)
Definition: timed_connect.c:67
int inet_windowsize
unsigned char * sa_family_list
Definition: inet_proto.h:21
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
#define NON_BLOCKING
Definition: iostuff.h:49
int non_blocking(int, int)
Definition: non_blocking.c:55
const char * host_port(char *buf, char **host, char *def_host, char **port, char *def_service)
Definition: host_port.c:115
int inet_connect(const char *addr, int block_mode, int timeout)
Definition: inet_connect.c:77
#define MAI_STRERROR(e)
Definition: myaddrinfo.h:169
void msg_info(const char *fmt,...)
Definition: msg.c:199