Annotation of embedaddon/miniupnpc/connecthostport.c, revision 1.1
1.1 ! misho 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 */
! 55: int 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:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>