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 73static int inet_connect_one(struct addrinfo *, int, int); 74 75/* inet_connect - connect to TCP listener */ 76 77int 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 138static 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) 153 set_inet_windowsize(sock, inet_windowsize); 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} 182