diff options
Diffstat (limited to 'src/btfrv.cpp')
| -rw-r--r-- | src/btfrv.cpp | 41 |
1 files changed, 26 insertions, 15 deletions
diff --git a/src/btfrv.cpp b/src/btfrv.cpp index d4f079f..133eb89 100644 --- a/src/btfrv.cpp +++ b/src/btfrv.cpp | |||
| @@ -102,31 +102,42 @@ static SOCKET ConnectTo(const char* host, unsigned short port) | |||
| 102 | #else | 102 | #else |
| 103 | struct addrinfo hints, *res = NULL; | 103 | struct addrinfo hints, *res = NULL; |
| 104 | memset(&hints, 0, sizeof(hints)); | 104 | memset(&hints, 0, sizeof(hints)); |
| 105 | hints.ai_family = AF_INET; | 105 | hints.ai_family = AF_UNSPEC; // IPv4 or IPv6 (some relays are v6-only) |
| 106 | hints.ai_socktype = SOCK_STREAM; | 106 | hints.ai_socktype = SOCK_STREAM; |
| 107 | char portstr[16]; sprintf(portstr, "%u", (unsigned)port); | 107 | char portstr[16]; sprintf(portstr, "%u", (unsigned)port); |
| 108 | if (getaddrinfo(host, portstr, &hints, &res) != 0 || !res) return INVALID_SOCKET; | 108 | if (getaddrinfo(host, portstr, &hints, &res) != 0 || !res) return INVALID_SOCKET; |
| 109 | SOCKET s = BtfSocketTag(socket(res->ai_family, res->ai_socktype, res->ai_protocol), SOCK_RV_DIAL); | ||
| 110 | if (s == INVALID_SOCKET) { freeaddrinfo(res); return INVALID_SOCKET; } | ||
| 111 | 109 | ||
| 112 | // Apply a short timeout only for the connect() and initial handshake so an | 110 | // Try each resolved address until one connects. |
| 113 | // unresponsive relay doesn't block the thread. Once the tunnel is live the | 111 | SOCKET s = INVALID_SOCKET; |
| 114 | // timeout is cleared -- a forwarding pipe must block indefinitely on recv(). | 112 | for (struct addrinfo* rp = res; rp != NULL; rp = rp->ai_next) |
| 113 | { | ||
| 114 | s = BtfSocketTag(socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol), SOCK_RV_DIAL); | ||
| 115 | if (s == INVALID_SOCKET) | ||
| 116 | continue; | ||
| 117 | |||
| 118 | // Apply a short timeout only for the connect() and initial handshake so an | ||
| 119 | // unresponsive relay doesn't block the thread. Once the tunnel is live the | ||
| 120 | // timeout is cleared -- a forwarding pipe must block indefinitely on recv(). | ||
| 115 | #ifdef _WIN32 | 121 | #ifdef _WIN32 |
| 116 | DWORD tvShort = 10000; | 122 | DWORD tvShort = 10000; |
| 117 | setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tvShort, sizeof(tvShort)); | 123 | setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tvShort, sizeof(tvShort)); |
| 118 | setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tvShort, sizeof(tvShort)); | 124 | setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tvShort, sizeof(tvShort)); |
| 119 | #else | 125 | #else |
| 120 | struct timeval tvShort; tvShort.tv_sec = 10; tvShort.tv_usec = 0; | 126 | struct timeval tvShort; tvShort.tv_sec = 10; tvShort.tv_usec = 0; |
| 121 | setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tvShort, sizeof(tvShort)); | 127 | setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&tvShort, sizeof(tvShort)); |
| 122 | setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &tvShort, sizeof(tvShort)); | 128 | setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*)&tvShort, sizeof(tvShort)); |
| 123 | #endif | 129 | #endif |
| 124 | 130 | ||
| 125 | if (connect(s, res->ai_addr, (int)res->ai_addrlen) != 0) | 131 | if (connect(s, rp->ai_addr, (int)rp->ai_addrlen) != 0) |
| 126 | { | 132 | { |
| 127 | CLOSESOCK(s); freeaddrinfo(res); return INVALID_SOCKET; | 133 | CLOSESOCK(s); |
| 134 | s = INVALID_SOCKET; | ||
| 135 | continue; | ||
| 136 | } | ||
| 137 | break; | ||
| 128 | } | 138 | } |
| 129 | freeaddrinfo(res); | 139 | freeaddrinfo(res); |
| 140 | if (s == INVALID_SOCKET) return INVALID_SOCKET; | ||
| 130 | #endif | 141 | #endif |
| 131 | 142 | ||
| 132 | // Clear the timeout -- the socket is now a live tunnel and must not | 143 | // Clear the timeout -- the socket is now a live tunnel and must not |