📄 socket.cpp
字号:
}
int Socket::read(void* aBuffer, int aBufLen, string &aIP) throw(SocketException) {
dcassert(type == TYPE_UDP);
sockaddr_in remote_addr = { 0 };
socklen_t addr_length = sizeof(remote_addr);
int len = check(::recvfrom(sock, (char*)aBuffer, aBufLen, 0, (sockaddr*)&remote_addr, &addr_length), true);
if(len > 0) {
aIP = inet_ntoa(remote_addr.sin_addr);
stats.totalDown += len;
} else {
aIP.clear();
}
return len;
}
int Socket::readAll(void* aBuffer, int aBufLen, u_int32_t timeout) throw(SocketException) {
u_int8_t* buf = (u_int8_t*)aBuffer;
int i = 0;
while(i < aBufLen) {
int j = read(buf + i, aBufLen - i);
if(j == 0) {
return i;
} else if(j == -1) {
if(wait(timeout, WAIT_READ) != WAIT_READ) {
return i;
}
continue;
}
i += j;
}
return i;
}
void Socket::writeAll(const void* aBuffer, int aLen, u_int32_t timeout) throw(SocketException) {
const u_int8_t* buf = (const u_int8_t*)aBuffer;
int pos = 0;
// No use sending more than this at a time...
int sendSize = getSocketOptInt(SO_SNDBUF);
while(pos < aLen) {
int i = write(buf+pos, (int)min(aLen-pos, sendSize));
if(i == -1) {
wait(timeout, WAIT_WRITE);
} else {
pos+=i;
stats.totalUp += i;
}
}
}
int Socket::write(const void* aBuffer, int aLen) throw(SocketException) {
int i = check(::send(sock, (const char*)aBuffer, aLen, 0), true);
if(i > 0) {
stats.totalUp += i;
// dcdebug("Out: %.*s\n", i, (char*)aBuffer);
}
return i;
}
/**
* Sends data, will block until all data has been sent or an exception occurs
* @param aBuffer Buffer with data
* @param aLen Data length
* @throw SocketExcpetion Send failed.
*/
void Socket::writeTo(const string& aAddr, short aPort, const void* aBuffer, int aLen, bool proxy) throw(SocketException) {
if(aLen <= 0)
return;
u_int8_t* buf = (u_int8_t*)aBuffer;
if(sock == INVALID_SOCKET) {
create(TYPE_UDP);
}
dcassert(type == TYPE_UDP);
sockaddr_in serv_addr;
if(aAddr.empty() || aPort == 0) {
throw SocketException(EADDRNOTAVAIL);
}
memset(&serv_addr, 0, sizeof(serv_addr));
if(SETTING(OUTGOING_CONNECTIONS) == SettingsManager::OUTGOING_SOCKS5 && proxy) {
if(udpServer.empty() || udpPort == 0) {
throw SocketException(STRING(SOCKS_SETUP_ERROR));
}
serv_addr.sin_port = htons(udpPort);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(udpServer.c_str());
string s = BOOLSETTING(SOCKS_RESOLVE) ? resolve(ip) : ip;
vector<u_int8_t> connStr;
connStr.push_back(0); // Reserved
connStr.push_back(0); // Reserved
connStr.push_back(0); // Fragment number, always 0 in our case...
if(BOOLSETTING(SOCKS_RESOLVE)) {
connStr.push_back(3);
connStr.push_back((u_int8_t)s.size());
connStr.insert(connStr.end(), aAddr.begin(), aAddr.end());
} else {
connStr.push_back(1); // Address type: IPv4;
unsigned long addr = inet_addr(resolve(aAddr).c_str());
u_int8_t* paddr = (u_int8_t*)&addr;
connStr.insert(connStr.end(), paddr, paddr+4);
}
connStr.insert(connStr.end(), buf, buf + aLen);
stats.totalUp += check(::sendto(sock, (const char*)&connStr[0], connStr.size(), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr)));
} else {
serv_addr.sin_port = htons(aPort);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(resolve(aAddr).c_str());
stats.totalUp += check(::sendto(sock, (const char*)aBuffer, (int)aLen, 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr)));
}
}
/**
* Blocks until timeout is reached one of the specified conditions have been fulfilled
* @param millis Max milliseconds to block.
* @param waitFor WAIT_*** flags that set what we're waiting for, set to the combination of flags that
* triggered the wait stop on return (==WAIT_NONE on timeout)
* @return WAIT_*** ored together of the current state.
* @throw SocketException Select or the connection attempt failed.
*/
int Socket::wait(u_int32_t millis, int waitFor) throw(SocketException) {
timeval tv;
fd_set rfd, wfd, efd;
fd_set *rfdp = NULL, *wfdp = NULL;
tv.tv_sec = millis/1000;
tv.tv_usec = (millis%1000)*1000;
if(waitFor & WAIT_CONNECT) {
dcassert(!(waitFor & WAIT_READ) && !(waitFor & WAIT_WRITE));
FD_ZERO(&wfd);
FD_ZERO(&efd);
FD_SET(sock, &wfd);
FD_SET(sock, &efd);
check(select((int)(sock+1), NULL, &wfd, &efd, &tv));
if(FD_ISSET(sock, &wfd) || FD_ISSET(sock, &efd)) {
int y = 0;
socklen_t z = sizeof(y);
check(getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&y, &z));
if(y != 0)
throw SocketException(y);
// No errors! We're connected (?)...
return WAIT_CONNECT;
}
return 0;
}
if(waitFor & WAIT_READ) {
dcassert(!(waitFor & WAIT_CONNECT));
rfdp = &rfd;
FD_ZERO(rfdp);
FD_SET(sock, rfdp);
}
if(waitFor & WAIT_WRITE) {
dcassert(!(waitFor & WAIT_CONNECT));
wfdp = &wfd;
FD_ZERO(wfdp);
FD_SET(sock, wfdp);
}
waitFor = WAIT_NONE;
check(select((int)(sock+1), rfdp, wfdp, NULL, &tv));
if(rfdp && FD_ISSET(sock, rfdp)) {
waitFor |= WAIT_READ;
}
if(wfdp && FD_ISSET(sock, wfdp)) {
waitFor |= WAIT_WRITE;
}
return waitFor;
}
string Socket::resolve(const string& aDns) {
sockaddr_in sock_addr;
memset(&sock_addr, 0, sizeof(sock_addr));
sock_addr.sin_port = 0;
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.s_addr = inet_addr(aDns.c_str());
if (sock_addr.sin_addr.s_addr == INADDR_NONE) { /* server address is a name or invalid */
hostent* host;
host = gethostbyname(aDns.c_str());
if (host == NULL) {
return Util::emptyString;
}
sock_addr.sin_addr.s_addr = *((u_int32_t*)host->h_addr);
return inet_ntoa(sock_addr.sin_addr);
} else {
return aDns;
}
}
string Socket::getLocalIp() throw() {
if(sock == INVALID_SOCKET)
return Util::emptyString;
sockaddr_in sock_addr;
socklen_t len = sizeof(sock_addr);
if(getsockname(sock, (sockaddr*)&sock_addr, &len) == 0) {
return inet_ntoa(sock_addr.sin_addr);
}
return Util::emptyString;
}
void Socket::socksUpdated() {
udpServer.clear();
udpPort = 0;
if(SETTING(OUTGOING_CONNECTIONS) == SettingsManager::OUTGOING_SOCKS5) {
try {
Socket s;
s.setBlocking(false);
s.connect(SETTING(SOCKS_SERVER), (short)SETTING(SOCKS_PORT));
s.socksAuth(SOCKS_TIMEOUT);
char connStr[10];
connStr[0] = 5; // SOCKSv5
connStr[1] = 3; // UDP Associate
connStr[2] = 0; // Reserved
connStr[3] = 1; // Address type: IPv4;
*((long*)(&connStr[4])) = 0; // No specific outgoing UDP address
*((u_int16_t*)(&connStr[8])) = 0; // No specific port...
s.writeAll(connStr, 10, SOCKS_TIMEOUT);
// We assume we'll get a ipv4 address back...therefore, 10 bytes...if not, things
// will break, but hey...noone's perfect (and I'm tired...)...
if(s.readAll(connStr, 10, SOCKS_TIMEOUT) != 10) {
return;
}
if(connStr[0] != 5 || connStr[1] != 0) {
return;
}
udpPort = (short)ntohs(*((u_int16_t*)(&connStr[8])));
in_addr serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.s_addr = *((long*)(&connStr[4]));
udpServer = inet_ntoa(serv_addr);
} catch(const SocketException&) {
dcdebug("Socket: Failed to register with socks server\n");
}
}
}
void Socket::shutdown() throw() {
if(sock != INVALID_SOCKET)
::shutdown(sock, 1);
}
void Socket::close() throw() {
if(sock != INVALID_SOCKET) {
#ifdef _WIN32
::closesocket(sock);
#else
::close(sock);
#endif
connected = false;
sock = INVALID_SOCKET;
}
}
void Socket::disconnect() throw() {
shutdown();
close();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -