/thirdparty/libportfwd/third-party/miniupnpc-1.6/connecthostport.c

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