summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorBruce Guenter <bruce@untroubled.org>2016-01-14 07:20:08 -0600
committerBruce Guenter <bruce@untroubled.org>2016-01-14 07:20:08 -0600
commit6c4434b5e1835c529c72243287df282dcf9650de (patch)
tree154bdecf240ed5aaab6679a1d5dbd27f4e81e4db /lib
parent894fcc11df471356d7ddff6bca7e2b4397c3e314 (diff)
parentaaf202655000d98ba15379cbd33f78527c5a5c36 (diff)
Merge branch 'ipv6'
Diffstat (limited to 'lib')
-rw-r--r--lib/tcpconnect.cc75
1 files changed, 60 insertions, 15 deletions
diff --git a/lib/tcpconnect.cc b/lib/tcpconnect.cc
index a140256..1d5f42f 100644
--- a/lib/tcpconnect.cc
+++ b/lib/tcpconnect.cc
@@ -26,21 +26,68 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <unistd.h>
#include "errcodes.h"
+#include "itoa.h"
#include "connect.h"
-static int sethostbyname(const mystring& hostname, struct sockaddr_in& sa)
+static int err_return(int errn, int dflt)
{
- struct hostent *he = gethostbyname(hostname.c_str());
- if(!he) {
- switch(h_errno) {
- case HOST_NOT_FOUND: return -ERR_HOST_NOT_FOUND;
- case NO_ADDRESS: return -ERR_NO_ADDRESS;
- case NO_RECOVERY: return -ERR_GHBN_FATAL;
- case TRY_AGAIN: return -ERR_GHBN_TEMP;
- default: return -ERR_GHBN_TEMP;
+ switch(errn) {
+ case HOST_NOT_FOUND: return -ERR_HOST_NOT_FOUND;
+ case NO_ADDRESS: return -ERR_NO_ADDRESS;
+ case NO_RECOVERY: return -ERR_GHBN_FATAL;
+ case TRY_AGAIN: return -ERR_GHBN_TEMP;
+ case EAI_AGAIN: return -ERR_GHBN_TEMP;
+ case EAI_NONAME: return -ERR_HOST_NOT_FOUND;
+ case EAI_FAIL: return -ERR_GHBN_FATAL;
+ case ECONNREFUSED: return -ERR_CONN_REFUSED;
+ case ETIMEDOUT: return -ERR_CONN_TIMEDOUT;
+ case ENETUNREACH: return -ERR_CONN_UNREACHABLE;
+ default: return -dflt;
+ }
+}
+
+#ifdef HAVE_GETADDRINFO
+
+int tcpconnect(const mystring& hostname, int port)
+{
+ struct addrinfo req, *res, *orig_res;
+ const char *service = itoa(port, 6);
+
+ memset(&req, 0, sizeof(req));
+ req.ai_flags = AI_NUMERICSERV;
+ req.ai_socktype = SOCK_STREAM;
+ int e = getaddrinfo(hostname.c_str(), service, &req, &res);
+ if(e)
+ return err_return(e, ERR_GHBN_TEMP);
+ int s = -1;
+ orig_res = res;
+
+ for (; res; res = res->ai_next ) {
+ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if(s > 0) {
+ if(connect(s, res->ai_addr, res->ai_addrlen) == 0)
+ break;
+ close(s);
+ s = -1;
}
}
+
+ freeaddrinfo(orig_res);
+
+ if(s < 0)
+ return err_return(errno, ERR_CONN_FAILED);
+ return s;
+}
+
+#else
+
+static int sethostbyname(const mystring& hostname, struct sockaddr_in& sa)
+{
+ struct hostent *he = gethostbyname(hostname.c_str());
+ if(!he)
+ return err_return(h_errno, ERR_GHBN_TEMP);
memcpy(&sa.sin_addr, he->h_addr, he->h_length);
return 0;
}
@@ -57,12 +104,10 @@ int tcpconnect(const mystring& hostname, int port)
if(s == -1)
return -ERR_SOCKET;
if(connect(s, (sockaddr*)&sa, sizeof(sa)) != 0) {
- switch(errno) {
- case ECONNREFUSED: return -ERR_CONN_REFUSED;
- case ETIMEDOUT: return -ERR_CONN_TIMEDOUT;
- case ENETUNREACH: return -ERR_CONN_UNREACHABLE;
- default: return -ERR_CONN_FAILED;
- }
+ close(s);
+ return err_return(errno, ERR_CONN_FAILED);
}
return s;
}
+
+#endif