blob: 0092d94dd02a8099e8b09e7843dd221b6674487c [file] [log] [blame]
Constantin Kaplinsky729598c2006-05-25 05:12:25 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19// -=- SocketManager.cxx
20
21#include <winsock2.h>
22#include <list>
23#include <rfb/LogWriter.h>
Pierre Ossmana4308c92018-10-26 15:54:56 +020024#include <rfb/Timer.h>
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000025#include <rfb_win32/SocketManager.h>
26
27using namespace rfb;
28using namespace rfb::win32;
29
30static LogWriter vlog("SocketManager");
31
32
33// -=- SocketManager
34
35SocketManager::SocketManager() {
36}
37
38SocketManager::~SocketManager() {
39}
40
41
Peter Åstrandf14f0d02008-12-09 10:48:44 +000042static void requestAddressChangeEvents(network::SocketListener* sock_) {
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000043 DWORD dummy = 0;
44 if (WSAIoctl(sock_->getFd(), SIO_ADDRESS_LIST_CHANGE, 0, 0, 0, 0, &dummy, 0, 0) == SOCKET_ERROR) {
45 DWORD err = WSAGetLastError();
46 if (err != WSAEWOULDBLOCK)
Pierre Ossmanad8609a2012-04-26 09:04:14 +000047 vlog.error("Unable to track address changes: 0x%08x", (unsigned)err);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000048 }
49}
50
51
52void SocketManager::addListener(network::SocketListener* sock_,
53 network::SocketServer* srvr,
54 AddressChangeNotifier* acn) {
55 WSAEVENT event = WSACreateEvent();
56 long flags = FD_ACCEPT | FD_CLOSE;
57 if (acn)
58 flags |= FD_ADDRESS_LIST_CHANGE;
59 try {
60 if (event && (WSAEventSelect(sock_->getFd(), event, flags) == SOCKET_ERROR))
61 throw rdr::SystemException("Unable to select on listener", WSAGetLastError());
62
63 // requestAddressChangeEvents MUST happen after WSAEventSelect, so that the socket is non-blocking
64 if (acn)
65 requestAddressChangeEvents(sock_);
66
67 // addEvent is the last thing we do, so that the event is NOT registered if previous steps fail
68 if (!event || !addEvent(event, this))
69 throw rdr::Exception("Unable to add listener");
70 } catch (rdr::Exception& e) {
71 if (event)
72 WSACloseEvent(event);
73 delete sock_;
Pierre Ossmanad8609a2012-04-26 09:04:14 +000074 vlog.error("%s", e.str());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000075 throw;
76 }
77
78 ListenInfo li;
79 li.sock = sock_;
80 li.server = srvr;
81 li.notifier = acn;
Pierre Ossman025326d2018-10-08 16:03:01 +020082 li.disable = false;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000083 listeners[event] = li;
84}
85
86void SocketManager::remListener(network::SocketListener* sock) {
87 std::map<HANDLE,ListenInfo>::iterator i;
88 for (i=listeners.begin(); i!=listeners.end(); i++) {
89 if (i->second.sock == sock) {
90 removeEvent(i->first);
91 WSACloseEvent(i->first);
92 delete sock;
93 listeners.erase(i);
94 return;
95 }
96 }
97 throw rdr::Exception("Listener not registered");
98}
99
100
101void SocketManager::addSocket(network::Socket* sock_, network::SocketServer* srvr, bool outgoing) {
102 WSAEVENT event = WSACreateEvent();
103 if (!event || !addEvent(event, this) ||
104 (WSAEventSelect(sock_->getFd(), event, FD_READ | FD_CLOSE) == SOCKET_ERROR)) {
105 if (event)
106 WSACloseEvent(event);
107 delete sock_;
108 vlog.error("Unable to add connection");
109 return;
110 }
111 ConnInfo ci;
112 ci.sock = sock_;
113 ci.server = srvr;
114 connections[event] = ci;
115 srvr->addSocket(sock_, outgoing);
116}
117
118void SocketManager::remSocket(network::Socket* sock_) {
119 std::map<HANDLE,ConnInfo>::iterator i;
120 for (i=connections.begin(); i!=connections.end(); i++) {
121 if (i->second.sock == sock_) {
122 i->second.server->removeSocket(sock_);
123 removeEvent(i->first);
124 WSACloseEvent(i->first);
125 delete sock_;
126 connections.erase(i);
127 return;
128 }
129 }
130 throw rdr::Exception("Socket not registered");
131}
132
Pierre Ossman025326d2018-10-08 16:03:01 +0200133bool SocketManager::getDisable(network::SocketServer* srvr)
134{
135 std::map<HANDLE,ListenInfo>::iterator i;
136 for (i=listeners.begin(); i!=listeners.end(); i++) {
137 if (i->second.server == srvr) {
138 return i->second.disable;
139 }
140 }
141 throw rdr::Exception("Listener not registered");
142}
143
144void SocketManager::setDisable(network::SocketServer* srvr, bool disable)
145{
146 bool found = false;
147 std::map<HANDLE,ListenInfo>::iterator i;
148 for (i=listeners.begin(); i!=listeners.end(); i++) {
149 if (i->second.server == srvr) {
150 i->second.disable = disable;
151 // There might be multiple sockets for the same server, so
152 // continue iterating
153 found = true;
154 }
155 }
156 if (!found)
157 throw rdr::Exception("Listener not registered");
158}
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000159
160int SocketManager::checkTimeouts() {
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000161 int timeout = EventManager::checkTimeouts();
162
163 std::map<HANDLE,ListenInfo>::iterator i;
164 for (i=listeners.begin(); i!=listeners.end(); i++)
Pierre Ossmana4308c92018-10-26 15:54:56 +0200165 soonestTimeout(&timeout, Timer::checkTimeouts());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000166
167 std::list<network::Socket*> shutdownSocks;
168 std::map<HANDLE,ConnInfo>::iterator j, j_next;
169 for (j=connections.begin(); j!=connections.end(); j=j_next) {
170 j_next = j; j_next++;
171 if (j->second.sock->isShutdown())
172 shutdownSocks.push_back(j->second.sock);
173 }
174
175 std::list<network::Socket*>::iterator k;
176 for (k=shutdownSocks.begin(); k!=shutdownSocks.end(); k++)
177 remSocket(*k);
178
179 return timeout;
180}
181
182
183void SocketManager::processEvent(HANDLE event) {
184 if (listeners.count(event)) {
185 ListenInfo li = listeners[event];
186
187 // Accept an incoming connection
188 vlog.debug("accepting incoming connection");
189
190 // What kind of event is this?
191 WSANETWORKEVENTS network_events;
192 WSAEnumNetworkEvents(li.sock->getFd(), event, &network_events);
193 if (network_events.lNetworkEvents & FD_ACCEPT) {
194 network::Socket* new_sock = li.sock->accept();
Pierre Ossman025326d2018-10-08 16:03:01 +0200195 if (new_sock && li.disable) {
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000196 delete new_sock;
197 new_sock = 0;
198 }
199 if (new_sock)
200 addSocket(new_sock, li.server, false);
201 } else if (network_events.lNetworkEvents & FD_CLOSE) {
202 vlog.info("deleting listening socket");
203 remListener(li.sock);
204 } else if (network_events.lNetworkEvents & FD_ADDRESS_LIST_CHANGE) {
Pierre Ossman79f82f92015-03-17 13:44:00 +0100205 li.notifier->processAddressChange();
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000206 requestAddressChangeEvents(li.sock);
207 } else {
208 vlog.error("unknown listener event: %lx", network_events.lNetworkEvents);
209 }
210 } else if (connections.count(event)) {
211 ConnInfo ci = connections[event];
212
213 try {
214 // Process data from an active connection
215
216 // Cancel event notification for this socket
217 if (WSAEventSelect(ci.sock->getFd(), event, 0) == SOCKET_ERROR)
218 throw rdr::SystemException("unable to disable WSAEventSelect:%u", WSAGetLastError());
219
220 // Reset the event object
221 WSAResetEvent(event);
222
223 // Call the socket server to process the event
Pierre Ossmand408ca52016-04-29 14:26:05 +0200224 ci.server->processSocketReadEvent(ci.sock);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000225 if (ci.sock->isShutdown()) {
226 remSocket(ci.sock);
227 return;
228 }
229
230 // Re-instate the required socket event
231 // If the read event is still valid, the event object gets set here
232 if (WSAEventSelect(ci.sock->getFd(), event, FD_READ | FD_CLOSE) == SOCKET_ERROR)
233 throw rdr::SystemException("unable to re-enable WSAEventSelect:%u", WSAGetLastError());
234 } catch (rdr::Exception& e) {
Pierre Ossmanad8609a2012-04-26 09:04:14 +0000235 vlog.error("%s", e.str());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000236 remSocket(ci.sock);
237 }
238 }
239}