📄 win32socketserver.cc
字号:
state_ = CS_CONNECTING; return 0;}voidWin32Socket::OnSocketNotify(int event, int error) { error_ = error; switch (event) { case FD_CONNECT: if (error != ERROR_SUCCESS) { ReportWSAError("WSAAsync:connect notify", error, addr_);#ifdef DEBUG int32 duration = utils_base::TimeDiff(talk_base::GetMillisecondCount(), connect_time_); LOG(LS_INFO) << "WSAAsync:connect error (" << duration << " ms), faking close";#endif Close(); // If you get an error connecting, close doesn't really do anything // and it certainly doesn't send back any close notification, but // we really only maintain a few states, so it is easiest to get // back into a known state by pretending that a close happened, even // though the connect event never did occur. SignalCloseEvent(this, error); } else {#ifdef DEBUG int32 duration = utils_base::TimeDiff(utils_base::GetMillisecondCount(), connect_time_); LOG(LS_INFO) << "WSAAsync:connect (" << duration << " ms)";#endif state_ = CS_CONNECTED; SignalConnectEvent(this); } break; case FD_ACCEPT: case FD_READ: if (error != ERROR_SUCCESS) { ReportWSAError("WSAAsync:read notify", error, addr_); Close(); } else { SignalReadEvent(this); } break; case FD_WRITE: if (error != ERROR_SUCCESS) { ReportWSAError("WSAAsync:write notify", error, addr_); Close(); } else { SignalWriteEvent(this); } break; case FD_CLOSE: ReportWSAError("WSAAsync:close notify", error, addr_); Close(); SignalCloseEvent(this, error); break; }}voidWin32Socket::OnDnsNotify(int ip, int error) { LOG_F(LS_INFO) << "(" << utils_base::SocketAddress::IPToString(ip) << ", " << error << ")"; if (error == 0) { utils_base::SocketAddress address(ip, dns_->port); sockaddr_in addr; address.ToSockAddr(&addr); error = DoConnect(addr); } else { Close(); } if (error) { error_ = error; SignalCloseEvent(this, error_); } else { delete dns_; dns_ = NULL; }}intWin32Socket::GetError() const { return error_;}voidWin32Socket::SetError(int error) { error_ = error;}Socket::ConnState Win32Socket::GetState() const { return state_;}int Win32Socket::SetOption(Option opt, int value) { ASSERT(opt == OPT_DONTFRAGMENT); value = (value == 0) ? 0 : 1; return ::setsockopt(socket_, IPPROTO_IP, IP_DONTFRAGMENT, reinterpret_cast<char*>(&value), sizeof(value));}intWin32Socket::Send(const void *pv, size_t cb) { int sent = ::send(socket_, reinterpret_cast<const char *>(pv), (int)cb, 0); UpdateLastError(); return sent;}intWin32Socket::SendTo(const void *pv, size_t cb, const utils_base::SocketAddress& addr) { sockaddr_in saddr; addr.ToSockAddr(&saddr); int sent = ::sendto(socket_, reinterpret_cast<const char *>(pv), (int)cb, 0, (sockaddr*)&saddr, sizeof(saddr)); UpdateLastError(); return sent;}int Win32Socket::Recv(void *pv, size_t cb) { int received = ::recv(socket_, (char *)pv, (int)cb, 0); UpdateLastError(); if (signal_close_ && (received > 0)) { char ch; if (::recv(socket_, &ch, 1, MSG_PEEK) <= 0) { signal_close_ = false; ::PostMessage(sink_->handle(), WM_SOCKETNOTIFY, WSAMAKESELECTREPLY(FD_CLOSE, 0), 0); } } return received;}intWin32Socket::RecvFrom(void *pv, size_t cb, utils_base::SocketAddress *paddr) { sockaddr_in saddr; socklen_t cbAddr = sizeof(saddr); int received = ::recvfrom(socket_, (char *)pv, (int)cb, 0, (sockaddr*)&saddr, &cbAddr); UpdateLastError(); if (received != SOCKET_ERROR) paddr->FromSockAddr(saddr); if (signal_close_ && (received > 0)) { char ch; if (::recv(socket_, &ch, 1, MSG_PEEK) <= 0) { signal_close_ = false; ::PostMessage(sink_->handle(), WM_SOCKETNOTIFY, WSAMAKESELECTREPLY(FD_CLOSE, 0), 0); } } return received;}int Win32Socket::Listen(int backlog) { int err = ::listen(socket_, backlog); UpdateLastError(); if (err == 0) state_ = CS_CONNECTING; return err;}utils_base::Socket* Win32Socket::Accept(utils_base::SocketAddress *paddr) { sockaddr_in saddr; socklen_t cbAddr = sizeof(saddr); SOCKET s = ::accept(socket_, (sockaddr*)&saddr, &cbAddr); UpdateLastError(); if (s == INVALID_SOCKET) return NULL; if (paddr) paddr->FromSockAddr(saddr); Win32Socket* socket = new Win32Socket; if (0 == socket->Attach(s)) return socket; delete socket; return NULL;}int Win32Socket::Close() { int err = 0; if (socket_ != INVALID_SOCKET) { err = ::closesocket(socket_); socket_ = INVALID_SOCKET; signal_close_ = false; UpdateLastError(); } if (dns_) { WSACancelAsyncRequest(dns_->handle); delete dns_; dns_ = NULL; } if (sink_) { sink_->Dispose(); sink_ = NULL; } memset(&addr_, 0, sizeof(addr_)); // no longer connected, zero ip/port state_ = CS_CLOSED; return err;}int Win32Socket::EstimateMTU(uint16* mtu) { utils_base::SocketAddress addr = GetRemoteAddress(); if (addr.IsAny()) { error_ = ENOTCONN; return -1; } utils_base::WinPing ping; if (!ping.IsValid()) { error_ = EINVAL; // can't think of a better error ID return -1; } for (int level = 0; PACKET_MAXIMUMS[level + 1] > 0; ++level) { int32 size = PACKET_MAXIMUMS[level] - IP_HEADER_SIZE - ICMP_HEADER_SIZE; utils_base::WinPing::PingResult result = ping.Ping(addr.ip(), size, 0, 1, false); if (result == utils_base::WinPing::PING_FAIL) { error_ = EINVAL; // can't think of a better error ID return -1; } if (result != utils_base::WinPing::PING_TOO_LARGE) { *mtu = PACKET_MAXIMUMS[level]; return 0; } } ASSERT(false); return 0;}boolWin32Socket::Create(long events) { ASSERT(NULL == sink_); if (INVALID_SOCKET == socket_) { socket_ = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, NULL, 0); if (socket_ == INVALID_SOCKET) { UpdateLastError(); return false; } } // Create window sink_ = new EventSink(this); sink_->Create(NULL, L"EventSink", 0, 0, 0, 0, 10, 10); // start the async select if (WSAAsyncSelect(socket_, sink_->handle(), WM_SOCKETNOTIFY, events) == SOCKET_ERROR) { UpdateLastError(); Close(); return false; } return true;}voidWin32Socket::UpdateLastError() { error_ = WSAGetLastError();}///////////////////////////////////////////////////////////////////////////////// Win32SocketServer///////////////////////////////////////////////////////////////////////////////static UINT s_wm_wakeup_id;LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp);// A socket server that provides cricket base services on top of a win32 gui threadWin32SocketServer::Win32SocketServer(MessageQueue *message_queue) { if (s_wm_wakeup_id == 0) s_wm_wakeup_id = RegisterWindowMessage(L"WM_WAKEUP"); message_queue_ = message_queue; hwnd_ = NULL; CreateDummyWindow();}Win32SocketServer::~Win32SocketServer() { if (hwnd_ != NULL) { KillTimer(hwnd_, 1); ::DestroyWindow(hwnd_); }}Socket* Win32SocketServer::CreateSocket(int type) { ASSERT(SOCK_STREAM == type); return new Win32Socket;}AsyncSocket* Win32SocketServer::CreateAsyncSocket(int type) { ASSERT(SOCK_STREAM == type); return new Win32Socket;}bool Win32SocketServer::Wait(int cms, bool process_io) { ASSERT(!process_io || (cms == 0)); // Should only be used for Thread::Send, or in Pump, below if (cms == -1) { MSG msg; GetMessage(&msg, NULL, s_wm_wakeup_id, s_wm_wakeup_id); } else if (cms != 0) { Sleep(cms); } return true;}void Win32SocketServer::WakeUp() { // Always post for every wakeup, so there are no // critical sections if (hwnd_ != NULL) PostMessage(hwnd_, s_wm_wakeup_id, 0, 0);}void Win32SocketServer::Pump() { // Process messages Message msg; while (message_queue_->Get(&msg, 0)) message_queue_->Dispatch(&msg); // Anything remaining? int delay = message_queue_->GetDelay(); if (delay == -1) { KillTimer(hwnd_, 1); } else { SetTimer(hwnd_, 1, delay, NULL); }}void Win32SocketServer::CreateDummyWindow(){ static bool s_registered; if (!s_registered) { ::WNDCLASSW wc; memset(&wc, 0, sizeof(wc)); wc.cbWndExtra = sizeof(this); wc.lpszClassName = L"Dummy"; wc.lpfnWndProc = DummyWndProc; ::RegisterClassW(&wc); s_registered = true; } hwnd_ = ::CreateWindowW(L"Dummy", L"", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL); SetWindowLong(hwnd_, GWL_USERDATA, (LONG)(LONG_PTR)this);}LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp){ if (wm == s_wm_wakeup_id || (wm == WM_TIMER && wp == 1)) { Win32SocketServer *ss = (Win32SocketServer *)(LONG_PTR)GetWindowLong(hwnd, GWL_USERDATA); ss->Pump(); return 0; } return ::DefWindowProc(hwnd, wm, wp, lp);}} // namespace talk_base
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -