📄 win32socketserver.cc
字号:
#include "byteorder.h"#include "common.h"#include "logging.h"#include "winping.h"#include "win32socketserver.h"#include "win32window.h"#include <ws2tcpip.h>namespace utils_base {///////////////////////////////////////////////////////////////////////////////// Win32Socket///////////////////////////////////////////////////////////////////////////////static const int kfRead = 0x0001;static const int kfWrite = 0x0002;// Standard MTUsstatic const uint16 PACKET_MAXIMUMS[] = { 65535, // Theoretical maximum, Hyperchannel 32000, // Nothing 17914, // 16Mb IBM Token Ring 8166, // IEEE 802.4 //4464, // IEEE 802.5 (4Mb max) 4352, // FDDI //2048, // Wideband Network 2002, // IEEE 802.5 (4Mb recommended) //1536, // Expermental Ethernet Networks //1500, // Ethernet, Point-to-Point (default) 1492, // IEEE 802.3 1006, // SLIP, ARPANET //576, // X.25 Networks //544, // DEC IP Portal //512, // NETBIOS 508, // IEEE 802/Source-Rt Bridge, ARCNET 296, // Point-to-Point (low delay) 68, // Official minimum 0, // End of list marker};static const uint32 IP_HEADER_SIZE = 20;static const uint32 ICMP_HEADER_SIZE = 8;#ifdef DEBUGLPCSTR WSAErrorToString(int error, LPCSTR *description_result) { LPCSTR string = "Unspecified"; LPCSTR description = "Unspecified description"; switch (error) { case ERROR_SUCCESS: string = "SUCCESS"; description = "Operation succeeded"; break; case WSAEWOULDBLOCK: string = "WSAEWOULDBLOCK"; description = "Using a non-blocking socket, will notify later"; break; case WSAEACCES: string = "WSAEACCES"; description = "Access denied, or sharing violation"; break; case WSAEADDRNOTAVAIL: string = "WSAEADDRNOTAVAIL"; description = "Address is not valid in this context"; break; case WSAENETDOWN: string = "WSAENETDOWN"; description = "Network is down"; break; case WSAENETUNREACH: string = "WSAENETUNREACH"; description = "Network is up, but unreachable"; break; case WSAENETRESET: string = "WSANETRESET"; description = "Connection has been reset due to keep-alive activity"; break; case WSAECONNABORTED: string = "WSAECONNABORTED"; description = "Aborted by host"; break; case WSAECONNRESET: string = "WSAECONNRESET"; description = "Connection reset by host"; break; case WSAETIMEDOUT: string = "WSAETIMEDOUT"; description = "Timed out, host failed to respond"; break; case WSAECONNREFUSED: string = "WSAECONNREFUSED"; description = "Host actively refused connection"; break; case WSAEHOSTDOWN: string = "WSAEHOSTDOWN"; description = "Host is down"; break; case WSAEHOSTUNREACH: string = "WSAEHOSTUNREACH"; description = "Host is unreachable"; break; case WSAHOST_NOT_FOUND: string = "WSAHOST_NOT_FOUND"; description = "No such host is known"; break; } if (description_result) { *description_result = description; } return string;}void ReportWSAError(LPCSTR context, int error, const sockaddr_in& addr) { talk_base::SocketAddress address; address.FromSockAddr(addr); LPCSTR description_string; LPCSTR error_string = WSAErrorToString(error, &description_string); LOG(LS_INFO) << context << " = " << error << " (" << error_string << ":" << description_string << ") [" << address.ToString() << "]";}#elsevoid ReportWSAError(LPCSTR context, int error, const sockaddr_in& addr) { }#endif/////////////////////////////////////////////////////////////////////////////// Win32Socket::EventSink/////////////////////////////////////////////////////////////////////////////#define WM_SOCKETNOTIFY (WM_USER + 50)#define WM_DNSNOTIFY (WM_USER + 51)struct Win32Socket::DnsLookup { HANDLE handle; uint16 port; char buffer[MAXGETHOSTSTRUCT];};class Win32Socket::EventSink : public Win32Window {public: EventSink(Win32Socket * parent) : parent_(parent) { } void Dispose(); virtual bool OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& result); virtual void OnFinalMessage(HWND hWnd);private: bool OnSocketNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& result); bool OnDnsNotify(WPARAM wParam, LPARAM lParam, LRESULT& result); Win32Socket * parent_;};voidWin32Socket::EventSink::Dispose() { parent_ = NULL; if (::IsWindow(handle())) { ::DestroyWindow(handle()); } else { delete this; }}bool Win32Socket::EventSink::OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& result) { switch (uMsg) { case WM_SOCKETNOTIFY: case WM_TIMER: return OnSocketNotify(uMsg, wParam, lParam, result); case WM_DNSNOTIFY: return OnDnsNotify(wParam, lParam, result); } return false;}boolWin32Socket::EventSink::OnSocketNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& result) { result = 0; // Make sure the socket isn't already closed if (!parent_ || (parent_->socket_ == INVALID_SOCKET)) return true; int event = WSAGETSELECTEVENT(lParam); int wsa_error = WSAGETSELECTERROR(lParam); if (uMsg == WM_TIMER) { event = FD_CLOSE; wsa_error = WSAETIMEDOUT; } else if (event == FD_CLOSE) { char ch; if (::recv(parent_->socket_, &ch, 1, MSG_PEEK) > 0) { parent_->signal_close_ = true; return true; } } parent_->OnSocketNotify(event, wsa_error); return true;}boolWin32Socket::EventSink::OnDnsNotify(WPARAM wParam, LPARAM lParam, LRESULT& result) { result = 0; if (!parent_) return true; if (!parent_->dns_ || (parent_->dns_->handle != reinterpret_cast<HANDLE>(wParam))) { ASSERT(false); return true; } uint32 ip = 0; int error = WSAGETASYNCERROR(lParam); if (error == 0) { hostent * pHost = reinterpret_cast<hostent *>(parent_->dns_->buffer); uint32 net_ip = *reinterpret_cast<uint32 *>(pHost->h_addr_list[0]); ip = utils_base::NetworkToHost32(net_ip); } parent_->OnDnsNotify(ip, error); return true;}voidWin32Socket::EventSink::OnFinalMessage(HWND hWnd) { delete this;}/////////////////////////////////////////////////////////////////////////////// Win32Socket/////////////////////////////////////////////////////////////////////////////Win32Socket::Win32Socket() : socket_(INVALID_SOCKET), error_(0), state_(CS_CLOSED), signal_close_(false), sink_(NULL), dns_(NULL) { // TODO: replace addr_ with SocketAddress memset(&addr_, 0, sizeof(addr_));}Win32Socket::~Win32Socket() { Close();}intWin32Socket::Attach(SOCKET s) { ASSERT(socket_ == INVALID_SOCKET); if (socket_ != INVALID_SOCKET) return SOCKET_ERROR; ASSERT(s != INVALID_SOCKET); if (s == INVALID_SOCKET) return SOCKET_ERROR; socket_ = s; state_ = CS_CONNECTED; if (!Create(FD_READ | FD_WRITE | FD_CLOSE)) return SOCKET_ERROR; return 0;}voidWin32Socket::SetTimeout(int ms) { if (sink_) ::SetTimer(sink_->handle(), 1, ms, 0);}utils_base::SocketAddressWin32Socket::GetLocalAddress() const { sockaddr_in addr; socklen_t addrlen = sizeof(addr); int result = ::getsockname(socket_, (sockaddr*)&addr, &addrlen); ASSERT(addrlen == sizeof(addr)); utils_base::SocketAddress address; if (result >= 0) { address.FromSockAddr(addr); } else { ASSERT(result >= 0); } return address;}utils_base::SocketAddress Win32Socket::GetRemoteAddress() const { sockaddr_in addr; socklen_t addrlen = sizeof(addr); int result = ::getpeername(socket_, (sockaddr*)&addr, &addrlen); ASSERT(addrlen == sizeof(addr)); utils_base::SocketAddress address; if (result >= 0) { address.FromSockAddr(addr); } else { ASSERT(errno == ENOTCONN); } return address;}intWin32Socket::Bind(const utils_base::SocketAddress& addr) { ASSERT(socket_ == INVALID_SOCKET); if (socket_ != INVALID_SOCKET) return SOCKET_ERROR; if (!Create(FD_ACCEPT | FD_CLOSE)) return SOCKET_ERROR; sockaddr_in saddr; addr.ToSockAddr(&saddr); int err = ::bind(socket_, (sockaddr*)&saddr, sizeof(saddr)); UpdateLastError(); return err;}intWin32Socket::Connect(const utils_base::SocketAddress& addr) { ASSERT(socket_ == INVALID_SOCKET); if (socket_ != INVALID_SOCKET) return SOCKET_ERROR; if (!Create(FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE)) return SOCKET_ERROR; if (!addr.IsUnresolved()) { sockaddr_in saddr; addr.ToSockAddr(&saddr); // now connect return DoConnect(saddr); } LOG_F(LS_INFO) << "async dns lookup (" << addr.IPAsString() << ")"; DnsLookup * dns = new DnsLookup; dns->handle = WSAAsyncGetHostByName(sink_->handle(), WM_DNSNOTIFY, addr.IPAsString().c_str(), dns->buffer, sizeof(dns->buffer)); if (!dns->handle) { LOG_F(LS_ERROR) << "WSAAsyncGetHostByName error: " << WSAGetLastError(); delete dns; UpdateLastError(); Close(); return SOCKET_ERROR; } dns->port = addr.port(); dns_ = dns; state_ = CS_CONNECTING; return 0;}intWin32Socket::DoConnect(const sockaddr_in& addr) { connect_time_ = utils_base::GetMillisecondCount(); int result = connect(socket_, (SOCKADDR*)&addr, sizeof(addr)); if (result == SOCKET_ERROR) { int code = WSAGetLastError(); if (code != WSAEWOULDBLOCK) { ReportWSAError("WSAAsync:connect", code, addr); error_ = code; Close(); return SOCKET_ERROR; } } addr_ = addr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -