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