276
by Razzloss
Copied dcpp/ from 0705-branch |
1 |
/*
|
2 |
* Copyright (C) 2001-2008 Jacek Sieka, arnetheduck on gmail point com
|
|
3 |
*
|
|
4 |
* This program is free software; you can redistribute it and/or modify
|
|
5 |
* it under the terms of the GNU General Public License as published by
|
|
6 |
* the Free Software Foundation; either version 2 of the License, or
|
|
7 |
* (at your option) any later version.
|
|
8 |
*
|
|
9 |
* This program is distributed in the hope that it will be useful,
|
|
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12 |
* GNU General Public License for more details.
|
|
13 |
*
|
|
14 |
* You should have received a copy of the GNU General Public License
|
|
15 |
* along with this program; if not, write to the Free Software
|
|
16 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
17 |
*/
|
|
18 |
||
19 |
#include "stdinc.h" |
|
20 |
#include "DCPlusPlus.h" |
|
21 |
||
22 |
#include "Socket.h" |
|
23 |
||
24 |
#include "SettingsManager.h" |
|
25 |
#include "TimerManager.h" |
|
26 |
||
27 |
namespace dcpp { |
|
28 |
||
29 |
string Socket::udpServer; |
|
30 |
uint16_t Socket::udpPort; |
|
31 |
||
32 |
#define checkconnected() if(!isConnected()) throw SocketException(ENOTCONN))
|
|
33 |
||
34 |
#ifdef _DEBUG
|
|
35 |
||
36 |
SocketException::SocketException(int aError) throw() { |
|
37 |
error = "SocketException: " + errorToString(aError); |
|
38 |
dcdebug("Thrown: %s\n", error.c_str()); |
|
39 |
}
|
|
40 |
||
41 |
#else // _DEBUG |
|
42 |
||
43 |
SocketException::SocketException(int aError) throw() : Exception(errorToString(aError)) { } |
|
44 |
||
45 |
#endif
|
|
46 |
||
47 |
Socket::Stats Socket::stats = { 0, 0 }; |
|
48 |
||
49 |
static const uint32_t SOCKS_TIMEOUT = 30000; |
|
50 |
||
51 |
string SocketException::errorToString(int aError) throw() { |
|
52 |
string msg = Util::translateError(aError); |
|
53 |
if(msg.empty()) { |
|
54 |
msg = str(F_("Unknown error: 0x%1$x") % aError); |
|
55 |
}
|
|
56 |
return msg; |
|
57 |
}
|
|
58 |
||
59 |
void Socket::create(int aType /* = TYPE_TCP */) throw(SocketException) { |
|
60 |
if(sock != INVALID_SOCKET) |
|
61 |
disconnect(); |
|
62 |
||
63 |
switch(aType) { |
|
64 |
case TYPE_TCP: |
|
65 |
sock = checksocket(socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)); |
|
66 |
break; |
|
67 |
case TYPE_UDP: |
|
68 |
sock = checksocket(socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)); |
|
69 |
break; |
|
70 |
default: |
|
71 |
dcasserta(0); |
|
72 |
}
|
|
73 |
type = aType; |
|
74 |
setBlocking(true); |
|
75 |
}
|
|
76 |
||
77 |
void Socket::accept(const Socket& listeningSocket) throw(SocketException) { |
|
78 |
if(sock != INVALID_SOCKET) { |
|
79 |
disconnect(); |
|
80 |
}
|
|
81 |
sockaddr_in sock_addr; |
|
82 |
socklen_t sz = sizeof(sock_addr); |
|
83 |
||
84 |
do { |
|
85 |
sock = ::accept(listeningSocket.sock, (sockaddr*)&sock_addr, &sz); |
|
86 |
} while (sock == SOCKET_ERROR && getLastError() == EINTR); |
|
87 |
check(sock); |
|
88 |
||
89 |
#ifdef _WIN32
|
|
90 |
// Make sure we disable any inherited windows message things for this socket.
|
|
91 |
::WSAAsyncSelect(sock, NULL, 0, 0); |
|
92 |
#endif
|
|
93 |
||
94 |
type = TYPE_TCP; |
|
95 |
||
96 |
setIp(inet_ntoa(sock_addr.sin_addr)); |
|
97 |
connected = true; |
|
98 |
setBlocking(true); |
|
99 |
}
|
|
100 |
||
101 |
||
102 |
uint16_t Socket::bind(uint16_t aPort, const string& aIp /* = 0.0.0.0 */) throw (SocketException){ |
|
103 |
sockaddr_in sock_addr; |
|
104 |
||
105 |
sock_addr.sin_family = AF_INET; |
|
106 |
sock_addr.sin_port = htons(aPort); |
|
107 |
sock_addr.sin_addr.s_addr = inet_addr(aIp.c_str()); |
|
108 |
if(::bind(sock, (sockaddr *)&sock_addr, sizeof(sock_addr)) == SOCKET_ERROR) { |
|
109 |
dcdebug("Bind failed, retrying with INADDR_ANY: %s\n", SocketException(getLastError()).getError().c_str()); |
|
110 |
sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); |
|
111 |
check(::bind(sock, (sockaddr *)&sock_addr, sizeof(sock_addr))); |
|
112 |
}
|
|
113 |
socklen_t size = sizeof(sock_addr); |
|
114 |
getsockname(sock, (sockaddr*)&sock_addr, (socklen_t*)&size); |
|
115 |
return ntohs(sock_addr.sin_port); |
|
116 |
}
|
|
117 |
||
118 |
void Socket::listen() throw(SocketException) { |
|
119 |
check(::listen(sock, 20)); |
|
120 |
connected = true; |
|
121 |
}
|
|
122 |
||
123 |
void Socket::connect(const string& aAddr, uint16_t aPort) throw(SocketException) { |
|
124 |
sockaddr_in serv_addr; |
|
125 |
||
126 |
if(sock == INVALID_SOCKET) { |
|
127 |
create(TYPE_TCP); |
|
128 |
}
|
|
129 |
||
130 |
string addr = resolve(aAddr); |
|
131 |
||
132 |
memset(&serv_addr, 0, sizeof(serv_addr)); |
|
133 |
serv_addr.sin_port = htons(aPort); |
|
134 |
serv_addr.sin_family = AF_INET; |
|
135 |
serv_addr.sin_addr.s_addr = inet_addr(addr.c_str()); |
|
136 |
||
137 |
int result; |
|
138 |
do { |
|
139 |
result = ::connect(sock,(sockaddr*)&serv_addr,sizeof(serv_addr)); |
|
140 |
} while (result < 0 && getLastError() == EINTR); |
|
141 |
check(result, true); |
|
142 |
||
143 |
connected = true; |
|
144 |
setIp(addr); |
|
145 |
}
|
|
146 |
||
147 |
namespace { |
|
148 |
inline uint32_t timeLeft(uint32_t start, uint32_t timeout) { |
|
149 |
if(timeout == 0) { |
|
150 |
return 0; |
|
151 |
}
|
|
152 |
uint64_t now = GET_TICK(); |
|
153 |
if(start + timeout < now) |
|
154 |
throw SocketException(_("Connection timeout")); |
|
155 |
return start + timeout - now; |
|
156 |
}
|
|
157 |
}
|
|
158 |
||
159 |
void Socket::socksConnect(const string& aAddr, uint16_t aPort, uint32_t timeout) throw(SocketException) { |
|
160 |
||
161 |
if(SETTING(SOCKS_SERVER).empty() || SETTING(SOCKS_PORT) == 0) { |
|
162 |
throw SocketException(_("The socks server failed establish a connection")); |
|
163 |
}
|
|
164 |
||
165 |
bool oldblock = getBlocking(); |
|
166 |
setBlocking(false); |
|
167 |
||
168 |
uint64_t start = GET_TICK(); |
|
169 |
||
170 |
connect(SETTING(SOCKS_SERVER), static_cast<uint16_t>(SETTING(SOCKS_PORT))); |
|
171 |
||
172 |
if(wait(timeLeft(start, timeout), WAIT_CONNECT) != WAIT_CONNECT) { |
|
173 |
throw SocketException(_("The socks server failed establish a connection")); |
|
174 |
}
|
|
175 |
||
176 |
socksAuth(timeLeft(start, timeout)); |
|
177 |
||
178 |
ByteVector connStr; |
|
179 |
||
180 |
// Authenticated, let's get on with it...
|
|
181 |
connStr.push_back(5); // SOCKSv5 |
|
182 |
connStr.push_back(1); // Connect |
|
183 |
connStr.push_back(0); // Reserved |
|
184 |
||
185 |
if(BOOLSETTING(SOCKS_RESOLVE)) { |
|
186 |
connStr.push_back(3); // Address type: domain name |
|
187 |
connStr.push_back((uint8_t)aAddr.size()); |
|
188 |
connStr.insert(connStr.end(), aAddr.begin(), aAddr.end()); |
|
189 |
} else { |
|
190 |
connStr.push_back(1); // Address type: IPv4; |
|
191 |
unsigned long addr = inet_addr(resolve(aAddr).c_str()); |
|
192 |
uint8_t* paddr = (uint8_t*)&addr; |
|
193 |
connStr.insert(connStr.end(), paddr, paddr+4); |
|
194 |
}
|
|
195 |
||
196 |
uint16_t port = htons(aPort); |
|
197 |
uint8_t* pport = (uint8_t*)&port; |
|
198 |
connStr.push_back(pport[0]); |
|
199 |
connStr.push_back(pport[1]); |
|
200 |
||
201 |
writeAll(&connStr[0], connStr.size(), timeLeft(start, timeout)); |
|
202 |
||
203 |
// We assume we'll get a ipv4 address back...therefore, 10 bytes...
|
|
204 |
/// @todo add support for ipv6
|
|
205 |
if(readAll(&connStr[0], 10, timeLeft(start, timeout)) != 10) { |
|
206 |
throw SocketException(_("The socks server failed establish a connection")); |
|
207 |
}
|
|
208 |
||
209 |
if(connStr[0] != 5 || connStr[1] != 0) { |
|
210 |
throw SocketException(_("The socks server failed establish a connection")); |
|
211 |
}
|
|
212 |
||
213 |
in_addr sock_addr; |
|
214 |
||
215 |
memset(&sock_addr, 0, sizeof(sock_addr)); |
|
216 |
sock_addr.s_addr = *((unsigned long*)&connStr[4]); |
|
217 |
setIp(inet_ntoa(sock_addr)); |
|
218 |
||
219 |
if(oldblock) |
|
220 |
setBlocking(oldblock); |
|
221 |
}
|
|
222 |
||
223 |
void Socket::socksAuth(uint32_t timeout) throw(SocketException) { |
|
224 |
vector<uint8_t> connStr; |
|
225 |
||
226 |
uint64_t start = GET_TICK(); |
|
227 |
||
228 |
if(SETTING(SOCKS_USER).empty() && SETTING(SOCKS_PASSWORD).empty()) { |
|
229 |
// No username and pw, easier...=)
|
|
230 |
connStr.push_back(5); // SOCKSv5 |
|
231 |
connStr.push_back(1); // 1 method |
|
232 |
connStr.push_back(0); // Method 0: No auth... |
|
233 |
||
234 |
writeAll(&connStr[0], 3, timeLeft(start, timeout)); |
|
235 |
||
236 |
if(readAll(&connStr[0], 2, timeLeft(start, timeout)) != 2) { |
|
237 |
throw SocketException(_("The socks server failed establish a connection")); |
|
238 |
}
|
|
239 |
||
240 |
if(connStr[1] != 0) { |
|
241 |
throw SocketException(_("The socks server requires authentication")); |
|
242 |
}
|
|
243 |
} else { |
|
244 |
// We try the username and password auth type (no, we don't support gssapi)
|
|
245 |
||
246 |
connStr.push_back(5); // SOCKSv5 |
|
247 |
connStr.push_back(1); // 1 method |
|
248 |
connStr.push_back(2); // Method 2: Name/Password... |
|
249 |
writeAll(&connStr[0], 3, timeLeft(start, timeout)); |
|
250 |
||
251 |
if(readAll(&connStr[0], 2, timeLeft(start, timeout)) != 2) { |
|
252 |
throw SocketException(_("The socks server failed establish a connection")); |
|
253 |
}
|
|
254 |
if(connStr[1] != 2) { |
|
255 |
throw SocketException(_("The socks server doesn't support login / password authentication")); |
|
256 |
}
|
|
257 |
||
258 |
connStr.clear(); |
|
259 |
// Now we send the username / pw...
|
|
260 |
connStr.push_back(1); |
|
261 |
connStr.push_back((uint8_t)SETTING(SOCKS_USER).length()); |
|
262 |
connStr.insert(connStr.end(), SETTING(SOCKS_USER).begin(), SETTING(SOCKS_USER).end()); |
|
263 |
connStr.push_back((uint8_t)SETTING(SOCKS_PASSWORD).length()); |
|
264 |
connStr.insert(connStr.end(), SETTING(SOCKS_PASSWORD).begin(), SETTING(SOCKS_PASSWORD).end()); |
|
265 |
||
266 |
writeAll(&connStr[0], connStr.size(), timeLeft(start, timeout)); |
|
267 |
||
268 |
if(readAll(&connStr[0], 2, timeLeft(start, timeout)) != 2) { |
|
269 |
throw SocketException(_("Socks server authentication failed (bad login / password?)")); |
|
270 |
}
|
|
271 |
||
272 |
if(connStr[1] != 0) { |
|
273 |
throw SocketException(_("Socks server authentication failed (bad login / password?)")); |
|
274 |
}
|
|
275 |
}
|
|
276 |
}
|
|
277 |
||
278 |
int Socket::getSocketOptInt(int option) throw(SocketException) { |
|
279 |
int val; |
|
280 |
socklen_t len = sizeof(val); |
|
281 |
check(::getsockopt(sock, SOL_SOCKET, option, (char*)&val, &len)); |
|
282 |
return val; |
|
283 |
}
|
|
284 |
||
285 |
void Socket::setSocketOpt(int option, int val) throw(SocketException) { |
|
286 |
int len = sizeof(val); |
|
287 |
check(::setsockopt(sock, SOL_SOCKET, option, (char*)&val, len)); |
|
288 |
}
|
|
289 |
||
290 |
int Socket::read(void* aBuffer, int aBufLen) throw(SocketException) { |
|
291 |
int len = 0; |
|
292 |
||
293 |
dcassert(type == TYPE_TCP || type == TYPE_UDP); |
|
294 |
do { |
|
295 |
if(type == TYPE_TCP) { |
|
296 |
len = ::recv(sock, (char*)aBuffer, aBufLen, 0); |
|
297 |
} else { |
|
298 |
len = ::recvfrom(sock, (char*)aBuffer, aBufLen, 0, NULL, NULL); |
|
299 |
}
|
|
300 |
} while (len < 0 && getLastError() == EINTR); |
|
301 |
check(len, true); |
|
302 |
||
303 |
if(len > 0) { |
|
304 |
stats.totalDown += len; |
|
305 |
}
|
|
306 |
||
307 |
return len; |
|
308 |
}
|
|
309 |
||
310 |
int Socket::read(void* aBuffer, int aBufLen, string &aIP) throw(SocketException) { |
|
311 |
dcassert(type == TYPE_UDP); |
|
312 |
||
313 |
sockaddr_in remote_addr = { 0 }; |
|
314 |
socklen_t addr_length = sizeof(remote_addr); |
|
315 |
||
316 |
int len; |
|
317 |
do { |
|
318 |
len = ::recvfrom(sock, (char*)aBuffer, aBufLen, 0, (sockaddr*)&remote_addr, &addr_length); |
|
319 |
} while (len < 0 && getLastError() == EINTR); |
|
320 |
||
321 |
check(len, true); |
|
322 |
if(len > 0) { |
|
323 |
aIP = inet_ntoa(remote_addr.sin_addr); |
|
324 |
stats.totalDown += len; |
|
325 |
} else { |
|
326 |
aIP.clear(); |
|
327 |
}
|
|
328 |
return len; |
|
329 |
}
|
|
330 |
||
331 |
int Socket::readAll(void* aBuffer, int aBufLen, uint32_t timeout) throw(SocketException) { |
|
332 |
uint8_t* buf = (uint8_t*)aBuffer; |
|
333 |
int i = 0; |
|
334 |
while(i < aBufLen) { |
|
335 |
int j = read(buf + i, aBufLen - i); |
|
336 |
if(j == 0) { |
|
337 |
return i; |
|
338 |
} else if(j == -1) { |
|
339 |
if(wait(timeout, WAIT_READ) != WAIT_READ) { |
|
340 |
return i; |
|
341 |
}
|
|
342 |
continue; |
|
343 |
}
|
|
344 |
||
345 |
i += j; |
|
346 |
}
|
|
347 |
return i; |
|
348 |
}
|
|
349 |
||
350 |
void Socket::writeAll(const void* aBuffer, int aLen, uint32_t timeout) throw(SocketException) { |
|
351 |
const uint8_t* buf = (const uint8_t*)aBuffer; |
|
352 |
int pos = 0; |
|
353 |
// No use sending more than this at a time...
|
|
354 |
int sendSize = getSocketOptInt(SO_SNDBUF); |
|
355 |
||
356 |
while(pos < aLen) { |
|
357 |
int i = write(buf+pos, (int)min(aLen-pos, sendSize)); |
|
358 |
if(i == -1) { |
|
359 |
wait(timeout, WAIT_WRITE); |
|
360 |
} else { |
|
361 |
pos+=i; |
|
362 |
stats.totalUp += i; |
|
363 |
}
|
|
364 |
}
|
|
365 |
}
|
|
366 |
||
367 |
int Socket::write(const void* aBuffer, int aLen) throw(SocketException) { |
|
368 |
int sent; |
|
369 |
do { |
|
370 |
sent = ::send(sock, (const char*)aBuffer, aLen, 0); |
|
371 |
} while (sent < 0 && getLastError() == EINTR); |
|
372 |
||
373 |
check(sent, true); |
|
374 |
if(sent > 0) { |
|
375 |
stats.totalUp += sent; |
|
376 |
}
|
|
377 |
return sent; |
|
378 |
}
|
|
379 |
||
380 |
/**
|
|
381 |
* Sends data, will block until all data has been sent or an exception occurs
|
|
382 |
* @param aBuffer Buffer with data
|
|
383 |
* @param aLen Data length
|
|
384 |
* @throw SocketExcpetion Send failed.
|
|
385 |
*/
|
|
386 |
void Socket::writeTo(const string& aAddr, uint16_t aPort, const void* aBuffer, int aLen, bool proxy) throw(SocketException) { |
|
387 |
if(aLen <= 0) |
|
388 |
return; |
|
389 |
||
390 |
uint8_t* buf = (uint8_t*)aBuffer; |
|
391 |
if(sock == INVALID_SOCKET) { |
|
392 |
create(TYPE_UDP); |
|
393 |
}
|
|
394 |
||
395 |
dcassert(type == TYPE_UDP); |
|
396 |
||
397 |
sockaddr_in serv_addr; |
|
398 |
||
399 |
if(aAddr.empty() || aPort == 0) { |
|
400 |
throw SocketException(EADDRNOTAVAIL); |
|
401 |
}
|
|
402 |
||
403 |
memset(&serv_addr, 0, sizeof(serv_addr)); |
|
404 |
||
405 |
int sent; |
|
406 |
if(SETTING(OUTGOING_CONNECTIONS) == SettingsManager::OUTGOING_SOCKS5 && proxy) { |
|
407 |
if(udpServer.empty() || udpPort == 0) { |
|
408 |
throw SocketException(_("Failed to set up the socks server for UDP relay (check socks address and port)")); |
|
409 |
}
|
|
410 |
||
411 |
serv_addr.sin_port = htons(udpPort); |
|
412 |
serv_addr.sin_family = AF_INET; |
|
413 |
serv_addr.sin_addr.s_addr = inet_addr(udpServer.c_str()); |
|
414 |
||
415 |
string s = BOOLSETTING(SOCKS_RESOLVE) ? resolve(ip) : ip; |
|
416 |
||
417 |
vector<uint8_t> connStr; |
|
418 |
||
419 |
connStr.push_back(0); // Reserved |
|
420 |
connStr.push_back(0); // Reserved |
|
421 |
connStr.push_back(0); // Fragment number, always 0 in our case... |
|
422 |
||
423 |
if(BOOLSETTING(SOCKS_RESOLVE)) { |
|
424 |
connStr.push_back(3); |
|
425 |
connStr.push_back((uint8_t)s.size()); |
|
426 |
connStr.insert(connStr.end(), aAddr.begin(), aAddr.end()); |
|
427 |
} else { |
|
428 |
connStr.push_back(1); // Address type: IPv4; |
|
429 |
unsigned long addr = inet_addr(resolve(aAddr).c_str()); |
|
430 |
uint8_t* paddr = (uint8_t*)&addr; |
|
431 |
connStr.insert(connStr.end(), paddr, paddr+4); |
|
432 |
}
|
|
433 |
||
434 |
connStr.insert(connStr.end(), buf, buf + aLen); |
|
435 |
||
436 |
do { |
|
437 |
sent = ::sendto(sock, (const char*)&connStr[0], connStr.size(), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); |
|
438 |
} while (sent < 0 && getLastError() == EINTR); |
|
439 |
} else { |
|
440 |
serv_addr.sin_port = htons(aPort); |
|
441 |
serv_addr.sin_family = AF_INET; |
|
442 |
serv_addr.sin_addr.s_addr = inet_addr(resolve(aAddr).c_str()); |
|
443 |
do { |
|
444 |
sent = ::sendto(sock, (const char*)aBuffer, (int)aLen, 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); |
|
445 |
} while (sent < 0 && getLastError() == EINTR); |
|
446 |
}
|
|
447 |
||
448 |
check(sent); |
|
449 |
stats.totalUp += sent; |
|
450 |
}
|
|
451 |
||
452 |
/**
|
|
453 |
* Blocks until timeout is reached one of the specified conditions have been fulfilled
|
|
454 |
* @param millis Max milliseconds to block.
|
|
455 |
* @param waitFor WAIT_*** flags that set what we're waiting for, set to the combination of flags that
|
|
456 |
* triggered the wait stop on return (==WAIT_NONE on timeout)
|
|
457 |
* @return WAIT_*** ored together of the current state.
|
|
458 |
* @throw SocketException Select or the connection attempt failed.
|
|
459 |
*/
|
|
460 |
int Socket::wait(uint32_t millis, int waitFor) throw(SocketException) { |
|
461 |
timeval tv; |
|
462 |
fd_set rfd, wfd, efd; |
|
463 |
fd_set *rfdp = NULL, *wfdp = NULL; |
|
464 |
tv.tv_sec = millis/1000; |
|
465 |
tv.tv_usec = (millis%1000)*1000; |
|
466 |
||
467 |
if(waitFor & WAIT_CONNECT) { |
|
468 |
dcassert(!(waitFor & WAIT_READ) && !(waitFor & WAIT_WRITE)); |
|
469 |
||
470 |
int result; |
|
471 |
do { |
|
472 |
FD_ZERO(&wfd); |
|
473 |
FD_ZERO(&efd); |
|
474 |
||
475 |
FD_SET(sock, &wfd); |
|
476 |
FD_SET(sock, &efd); |
|
477 |
result = select((int)(sock+1), 0, &wfd, &efd, &tv); |
|
478 |
} while (result < 0 && getLastError() == EINTR); |
|
479 |
check(result); |
|
480 |
||
481 |
if(FD_ISSET(sock, &wfd)) { |
|
482 |
return WAIT_CONNECT; |
|
483 |
}
|
|
484 |
||
485 |
if(FD_ISSET(sock, &efd)) { |
|
486 |
int y = 0; |
|
487 |
socklen_t z = sizeof(y); |
|
488 |
check(getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&y, &z)); |
|
489 |
||
490 |
if(y != 0) |
|
491 |
throw SocketException(y); |
|
492 |
// No errors! We're connected (?)...
|
|
493 |
return WAIT_CONNECT; |
|
494 |
}
|
|
495 |
return 0; |
|
496 |
}
|
|
497 |
||
498 |
int result; |
|
499 |
do { |
|
500 |
if(waitFor & WAIT_READ) { |
|
501 |
dcassert(!(waitFor & WAIT_CONNECT)); |
|
502 |
rfdp = &rfd; |
|
503 |
FD_ZERO(rfdp); |
|
504 |
FD_SET(sock, rfdp); |
|
505 |
}
|
|
506 |
if(waitFor & WAIT_WRITE) { |
|
507 |
dcassert(!(waitFor & WAIT_CONNECT)); |
|
508 |
wfdp = &wfd; |
|
509 |
FD_ZERO(wfdp); |
|
510 |
FD_SET(sock, wfdp); |
|
511 |
}
|
|
512 |
||
513 |
result = select((int)(sock+1), rfdp, wfdp, NULL, &tv); |
|
514 |
} while (result < 0 && getLastError() == EINTR); |
|
515 |
check(result); |
|
516 |
||
517 |
waitFor = WAIT_NONE; |
|
518 |
||
519 |
if(rfdp && FD_ISSET(sock, rfdp)) { |
|
520 |
waitFor |= WAIT_READ; |
|
521 |
}
|
|
522 |
if(wfdp && FD_ISSET(sock, wfdp)) { |
|
523 |
waitFor |= WAIT_WRITE; |
|
524 |
}
|
|
525 |
||
526 |
return waitFor; |
|
527 |
}
|
|
528 |
||
529 |
string Socket::resolve(const string& aDns) { |
|
530 |
sockaddr_in sock_addr; |
|
531 |
||
532 |
memset(&sock_addr, 0, sizeof(sock_addr)); |
|
533 |
sock_addr.sin_port = 0; |
|
534 |
sock_addr.sin_family = AF_INET; |
|
535 |
sock_addr.sin_addr.s_addr = inet_addr(aDns.c_str()); |
|
536 |
||
537 |
if (sock_addr.sin_addr.s_addr == INADDR_NONE) { /* server address is a name or invalid */ |
|
538 |
hostent* host; |
|
539 |
host = gethostbyname(aDns.c_str()); |
|
540 |
if (host == NULL) { |
|
541 |
return Util::emptyString; |
|
542 |
}
|
|
543 |
sock_addr.sin_addr.s_addr = *((uint32_t*)host->h_addr); |
|
544 |
return inet_ntoa(sock_addr.sin_addr); |
|
545 |
} else { |
|
546 |
return aDns; |
|
547 |
}
|
|
548 |
}
|
|
549 |
||
550 |
string Socket::getLocalIp() throw() { |
|
551 |
if(sock == INVALID_SOCKET) |
|
552 |
return Util::emptyString; |
|
553 |
||
554 |
sockaddr_in sock_addr; |
|
555 |
socklen_t len = sizeof(sock_addr); |
|
556 |
if(getsockname(sock, (sockaddr*)&sock_addr, &len) == 0) { |
|
557 |
return inet_ntoa(sock_addr.sin_addr); |
|
558 |
}
|
|
559 |
return Util::emptyString; |
|
560 |
}
|
|
561 |
||
562 |
void Socket::socksUpdated() { |
|
563 |
udpServer.clear(); |
|
564 |
udpPort = 0; |
|
565 |
||
566 |
if(SETTING(OUTGOING_CONNECTIONS) == SettingsManager::OUTGOING_SOCKS5) { |
|
567 |
try { |
|
568 |
Socket s; |
|
569 |
s.setBlocking(false); |
|
570 |
s.connect(SETTING(SOCKS_SERVER), static_cast<uint16_t>(SETTING(SOCKS_PORT))); |
|
571 |
s.socksAuth(SOCKS_TIMEOUT); |
|
572 |
||
573 |
char connStr[10]; |
|
574 |
connStr[0] = 5; // SOCKSv5 |
|
575 |
connStr[1] = 3; // UDP Associate |
|
576 |
connStr[2] = 0; // Reserved |
|
577 |
connStr[3] = 1; // Address type: IPv4; |
|
578 |
*((long*)(&connStr[4])) = 0; // No specific outgoing UDP address |
|
579 |
*((uint16_t*)(&connStr[8])) = 0; // No specific port... |
|
580 |
||
581 |
s.writeAll(connStr, 10, SOCKS_TIMEOUT); |
|
582 |
||
583 |
// We assume we'll get a ipv4 address back...therefore, 10 bytes...if not, things
|
|
584 |
// will break, but hey...noone's perfect (and I'm tired...)...
|
|
585 |
if(s.readAll(connStr, 10, SOCKS_TIMEOUT) != 10) { |
|
586 |
return; |
|
587 |
}
|
|
588 |
||
589 |
if(connStr[0] != 5 || connStr[1] != 0) { |
|
590 |
return; |
|
591 |
}
|
|
592 |
||
593 |
udpPort = static_cast<uint16_t>(ntohs(*((uint16_t*)(&connStr[8])))); |
|
594 |
||
595 |
in_addr serv_addr; |
|
596 |
||
597 |
memset(&serv_addr, 0, sizeof(serv_addr)); |
|
598 |
serv_addr.s_addr = *((long*)(&connStr[4])); |
|
599 |
udpServer = inet_ntoa(serv_addr); |
|
600 |
} catch(const SocketException&) { |
|
601 |
dcdebug("Socket: Failed to register with socks server\n"); |
|
602 |
}
|
|
603 |
}
|
|
604 |
}
|
|
605 |
||
606 |
void Socket::shutdown() throw() { |
|
607 |
if(sock != INVALID_SOCKET) |
|
608 |
::shutdown(sock, 2); |
|
609 |
}
|
|
610 |
||
611 |
void Socket::close() throw() { |
|
612 |
if(sock != INVALID_SOCKET) { |
|
613 |
#ifdef _WIN32
|
|
614 |
::closesocket(sock); |
|
615 |
#else
|
|
616 |
::close(sock); |
|
617 |
#endif
|
|
618 |
connected = false; |
|
619 |
sock = INVALID_SOCKET; |
|
620 |
}
|
|
621 |
}
|
|
622 |
||
623 |
void Socket::disconnect() throw() { |
|
624 |
shutdown(); |
|
625 |
close(); |
|
626 |
}
|
|
627 |
||
628 |
} // namespace dcpp |