1 /* $NetBSD: inet_connect.c,v 1.2 2022/10/08 16:12:50 christos 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 /* Wietse Venema 52 /* Google, Inc. 53 /* 111 8th Avenue 54 /* New York, NY 10011, USA 55 /*--*/ 56 57 /* System interfaces. */ 58 59 #include <sys_defs.h> 60 #include <sys/socket.h> 61 #include <netinet/in.h> 62 #include <string.h> 63 #include <unistd.h> 64 #include <errno.h> 65 #include <netdb.h> 66 67 /* Utility library. */ 68 69 #include "mymalloc.h" 70 #include "msg.h" 71 #include "iostuff.h" 72 #include "host_port.h" 73 #include "sane_connect.h" 74 #include "connect.h" 75 #include "timed_connect.h" 76 #include "myaddrinfo.h" 77 #include "sock_addr.h" 78 #include "inet_proto.h" 79 80 static int inet_connect_one(struct addrinfo *, int, int); 81 82 /* inet_connect - connect to TCP listener */ 83 84 int inet_connect(const char *addr, int block_mode, int timeout) 85 { 86 char *buf; 87 char *host; 88 char *port; 89 const char *parse_err; 90 struct addrinfo *res; 91 struct addrinfo *res0; 92 int aierr; 93 int sock; 94 MAI_HOSTADDR_STR hostaddr; 95 const INET_PROTO_INFO *proto_info; 96 int found; 97 98 /* 99 * Translate address information to internal form. No host defaults to 100 * the local host. 101 */ 102 buf = mystrdup(addr); 103 if ((parse_err = host_port(buf, &host, "localhost", &port, (char *) 0)) != 0) 104 msg_fatal("%s: %s", addr, parse_err); 105 if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res0)) != 0) 106 msg_warn("host or service %s not found: %s", 107 addr, MAI_STRERROR(aierr)); 108 myfree(buf); 109 if (aierr) { 110 errno = EADDRNOTAVAIL; /* for up-stream "%m" */ 111 return (-1); 112 } 113 proto_info = inet_proto_info(); 114 for (sock = -1, found = 0, res = res0; res != 0; res = res->ai_next) { 115 116 /* 117 * Safety net. 118 */ 119 if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) { 120 msg_info("skipping address family %d for host %s", 121 res->ai_family, host); 122 continue; 123 } 124 found++; 125 126 /* 127 * In case of multiple addresses, show what address we're trying now. 128 */ 129 if (msg_verbose) { 130 SOCKADDR_TO_HOSTADDR(res->ai_addr, res->ai_addrlen, 131 &hostaddr, (MAI_SERVPORT_STR *) 0, 0); 132 msg_info("trying... [%s]", hostaddr.buf); 133 } 134 if ((sock = inet_connect_one(res, block_mode, timeout)) < 0) { 135 if (msg_verbose) 136 msg_info("%m"); 137 } else 138 break; 139 } 140 if (found == 0) 141 msg_fatal("host not found: %s", addr); 142 freeaddrinfo(res0); 143 return (sock); 144 } 145 146 /* inet_connect_one - try to connect to one address */ 147 148 static int inet_connect_one(struct addrinfo * res, int block_mode, int timeout) 149 { 150 int sock; 151 152 /* 153 * Create a client socket. 154 */ 155 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 156 if (sock < 0) 157 return (-1); 158 159 /* 160 * Window scaling workaround. 161 */ 162 if (inet_windowsize > 0) 163 set_inet_windowsize(sock, inet_windowsize); 164 165 /* 166 * Timed connect. 167 */ 168 if (timeout > 0) { 169 non_blocking(sock, NON_BLOCKING); 170 if (timed_connect(sock, res->ai_addr, res->ai_addrlen, timeout) < 0) { 171 close(sock); 172 return (-1); 173 } 174 if (block_mode != NON_BLOCKING) 175 non_blocking(sock, block_mode); 176 return (sock); 177 } 178 179 /* 180 * Maybe block until connected. 181 */ 182 else { 183 non_blocking(sock, block_mode); 184 if (sane_connect(sock, res->ai_addr, res->ai_addrlen) < 0 185 && errno != EINPROGRESS) { 186 close(sock); 187 return (-1); 188 } 189 return (sock); 190 } 191 } 192