/thirdparty/libportfwd/third-party/miniupnpc-1.6/connecthostport.c
C | 241 lines | 209 code | 8 blank | 24 comment | 40 complexity | cdfbd26dd4cd0cb6319dad83b408b5ac MD5 | raw file
1/* $Id: connecthostport.c,v 1.5 2011/04/09 08:49:50 nanard Exp $ */ 2/* Project : miniupnp 3 * Author : Thomas Bernard 4 * Copyright (c) 2010-2011 Thomas Bernard 5 * This software is subject to the conditions detailed in the 6 * LICENCE file provided in this distribution. */ 7 8/* use getaddrinfo() or gethostbyname() 9 * uncomment the following line in order to use gethostbyname() */ 10#ifdef NO_GETADDRINFO 11#define USE_GETHOSTBYNAME 12#endif 13 14#include <string.h> 15#include <stdio.h> 16#ifdef WIN32 17#include <winsock2.h> 18#include <ws2tcpip.h> 19#include <io.h> 20#define MAXHOSTNAMELEN 64 21#define snprintf _snprintf 22#define herror 23#define socklen_t int 24#else /* #ifdef WIN32 */ 25#include <unistd.h> 26#include <sys/param.h> 27#include <errno.h> 28#define closesocket close 29#include <netdb.h> 30/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions 31 * during the connect() call */ 32#define MINIUPNPC_IGNORE_EINTR 33#ifndef USE_GETHOSTBYNAME 34#include <sys/types.h> 35#include <sys/socket.h> 36#endif /* #ifndef USE_GETHOSTBYNAME */ 37#endif /* #else WIN32 */ 38 39/* definition of PRINT_SOCKET_ERROR */ 40#ifdef WIN32 41#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); 42#else 43#define PRINT_SOCKET_ERROR(x) perror(x) 44#endif 45 46#if defined(__amigaos__) || defined(__amigaos4__) 47#define herror(A) printf("%s\n", A) 48#endif 49 50#include "connecthostport.h" 51 52/* connecthostport() 53 * return a socket connected (TCP) to the host and port 54 * or -1 in case of error */ 55int connecthostport(const char * host, unsigned short port) 56{ 57 int s, n; 58#ifdef USE_GETHOSTBYNAME 59 struct sockaddr_in dest; 60 struct hostent *hp; 61#else /* #ifdef USE_GETHOSTBYNAME */ 62 char tmp_host[MAXHOSTNAMELEN+1]; 63 char port_str[8]; 64 struct addrinfo *ai, *p; 65 struct addrinfo hints; 66#endif /* #ifdef USE_GETHOSTBYNAME */ 67#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT 68 struct timeval timeout; 69#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ 70 71#ifdef USE_GETHOSTBYNAME 72 hp = gethostbyname(host); 73 if(hp == NULL) 74 { 75 herror(host); 76 return -1; 77 } 78 memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr)); 79 memset(dest.sin_zero, 0, sizeof(dest.sin_zero)); 80 s = socket(PF_INET, SOCK_STREAM, 0); 81 if(s < 0) 82 { 83 PRINT_SOCKET_ERROR("socket"); 84 return -1; 85 } 86#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT 87 /* setting a 3 seconds timeout for the connect() call */ 88 timeout.tv_sec = 3; 89 timeout.tv_usec = 0; 90 if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) 91 { 92 PRINT_SOCKET_ERROR("setsockopt"); 93 } 94 timeout.tv_sec = 3; 95 timeout.tv_usec = 0; 96 if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) 97 { 98 PRINT_SOCKET_ERROR("setsockopt"); 99 } 100#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ 101 dest.sin_family = AF_INET; 102 dest.sin_port = htons(port); 103 n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in)); 104#ifdef MINIUPNPC_IGNORE_EINTR 105 while(n < 0 && errno == EINTR) 106 { 107 socklen_t len; 108 fd_set wset; 109 int err; 110 FD_ZERO(&wset); 111 FD_SET(s, &wset); 112 if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) 113 continue; 114 /*len = 0;*/ 115 /*n = getpeername(s, NULL, &len);*/ 116 len = sizeof(err); 117 if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { 118 PRINT_SOCKET_ERROR("getsockopt"); 119 closesocket(s); 120 return -1; 121 } 122 if(err != 0) { 123 errno = err; 124 n = -1; 125 } 126 } 127#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ 128 if(n<0) 129 { 130 PRINT_SOCKET_ERROR("connect"); 131 closesocket(s); 132 return -1; 133 } 134#else /* #ifdef USE_GETHOSTBYNAME */ 135 /* use getaddrinfo() instead of gethostbyname() */ 136 memset(&hints, 0, sizeof(hints)); 137 /* hints.ai_flags = AI_ADDRCONFIG; */ 138#ifdef AI_NUMERICSERV 139 hints.ai_flags = AI_NUMERICSERV; 140#endif 141 hints.ai_socktype = SOCK_STREAM; 142 hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */ 143 /* hints.ai_protocol = IPPROTO_TCP; */ 144 snprintf(port_str, sizeof(port_str), "%hu", port); 145 if(host[0] == '[') 146 { 147 /* literal ip v6 address */ 148 int i; 149 for(i = 0; host[i+1] && (host[i+1] != ']') && i < MAXHOSTNAMELEN; i++) 150 { 151 tmp_host[i] = host[i+1]; 152 } 153 tmp_host[i] = '\0'; 154 } 155 else 156 { 157 strncpy(tmp_host, host, MAXHOSTNAMELEN); 158 } 159 tmp_host[MAXHOSTNAMELEN] = '\0'; 160 n = getaddrinfo(tmp_host, port_str, &hints, &ai); 161 if(n != 0) 162 { 163#ifdef WIN32 164 fprintf(stderr, "getaddrinfo() error : %d\n", n); 165#else 166 fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n)); 167#endif 168 return -1; 169 } 170 s = -1; 171 for(p = ai; p; p = p->ai_next) 172 { 173 s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); 174 if(s < 0) 175 continue; 176#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT 177 /* setting a 3 seconds timeout for the connect() call */ 178 timeout.tv_sec = 3; 179 timeout.tv_usec = 0; 180 if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) 181 { 182 PRINT_SOCKET_ERROR("setsockopt"); 183 } 184 timeout.tv_sec = 3; 185 timeout.tv_usec = 0; 186 if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) 187 { 188 PRINT_SOCKET_ERROR("setsockopt"); 189 } 190#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ 191 n = connect(s, p->ai_addr, p->ai_addrlen); 192#ifdef MINIUPNPC_IGNORE_EINTR 193 while(n < 0 && errno == EINTR) 194 { 195 socklen_t len; 196 fd_set wset; 197 int err; 198 FD_ZERO(&wset); 199 FD_SET(s, &wset); 200 if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) 201 continue; 202 /*len = 0;*/ 203 /*n = getpeername(s, NULL, &len);*/ 204 len = sizeof(err); 205 if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { 206 PRINT_SOCKET_ERROR("getsockopt"); 207 closesocket(s); 208 freeaddrinfo(ai); 209 return -1; 210 } 211 if(err != 0) { 212 errno = err; 213 n = -1; 214 } 215 } 216#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ 217 if(n < 0) 218 { 219 closesocket(s); 220 continue; 221 } 222 else 223 { 224 break; 225 } 226 } 227 freeaddrinfo(ai); 228 if(s < 0) 229 { 230 PRINT_SOCKET_ERROR("socket"); 231 return -1; 232 } 233 if(n < 0) 234 { 235 PRINT_SOCKET_ERROR("connect"); 236 return -1; 237 } 238#endif /* #ifdef USE_GETHOSTBYNAME */ 239 return s; 240} 241