blob: aa469e53685bc97eefeeda3a5590ddaa6c874a30 [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>
24#include <rfb_win32/SocketManager.h>
25
26using namespace rfb;
27using namespace rfb::win32;
28
29static LogWriter vlog("SocketManager");
30
31
32// -=- SocketManager
33
34SocketManager::SocketManager() {
35}
36
37SocketManager::~SocketManager() {
38}
39
40
Peter Åstrandf14f0d02008-12-09 10:48:44 +000041static void requestAddressChangeEvents(network::SocketListener* sock_) {
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000042 DWORD dummy = 0;
43 if (WSAIoctl(sock_->getFd(), SIO_ADDRESS_LIST_CHANGE, 0, 0, 0, 0, &dummy, 0, 0) == SOCKET_ERROR) {
44 DWORD err = WSAGetLastError();
45 if (err != WSAEWOULDBLOCK)
Pierre Ossmanad8609a2012-04-26 09:04:14 +000046 vlog.error("Unable to track address changes: 0x%08x", (unsigned)err);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000047 }
48}
49
50
51void SocketManager::addListener(network::SocketListener* sock_,
52 network::SocketServer* srvr,
53 AddressChangeNotifier* acn) {
54 WSAEVENT event = WSACreateEvent();
55 long flags = FD_ACCEPT | FD_CLOSE;
56 if (acn)
57 flags |= FD_ADDRESS_LIST_CHANGE;
58 try {
59 if (event && (WSAEventSelect(sock_->getFd(), event, flags) == SOCKET_ERROR))
60 throw rdr::SystemException("Unable to select on listener", WSAGetLastError());
61
62 // requestAddressChangeEvents MUST happen after WSAEventSelect, so that the socket is non-blocking
63 if (acn)
64 requestAddressChangeEvents(sock_);
65
66 // addEvent is the last thing we do, so that the event is NOT registered if previous steps fail
67 if (!event || !addEvent(event, this))
68 throw rdr::Exception("Unable to add listener");
69 } catch (rdr::Exception& e) {
70 if (event)
71 WSACloseEvent(event);
72 delete sock_;
Pierre Ossmanad8609a2012-04-26 09:04:14 +000073 vlog.error("%s", e.str());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000074 throw;
75 }
76
77 ListenInfo li;
78 li.sock = sock_;
79 li.server = srvr;
80 li.notifier = acn;
Pierre Ossman025326d2018-10-08 16:03:01 +020081 li.disable = false;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000082 listeners[event] = li;
83}
84
85void SocketManager::remListener(network::SocketListener* sock) {
86 std::map<HANDLE,ListenInfo>::iterator i;
87 for (i=listeners.begin(); i!=listeners.end(); i++) {
88 if (i->second.sock == sock) {
89 removeEvent(i->first);
90 WSACloseEvent(i->first);
91 delete sock;
92 listeners.erase(i);
93 return;
94 }
95 }
96 throw rdr::Exception("Listener not registered");
97}
98
99
100void SocketManager::addSocket(network::Socket* sock_, network::SocketServer* srvr, bool outgoing) {
101 WSAEVENT event = WSACreateEvent();
102 if (!event || !addEvent(event, this) ||
103 (WSAEventSelect(sock_->getFd(), event, FD_READ | FD_CLOSE) == SOCKET_ERROR)) {
104 if (event)
105 WSACloseEvent(event);
106 delete sock_;
107 vlog.error("Unable to add connection");
108 return;
109 }
110 ConnInfo ci;
111 ci.sock = sock_;
112 ci.server = srvr;
113 connections[event] = ci;
114 srvr->addSocket(sock_, outgoing);
115}
116
117void SocketManager::remSocket(network::Socket* sock_) {
118 std::map<HANDLE,ConnInfo>::iterator i;
119 for (i=connections.begin(); i!=connections.end(); i++) {
120 if (i->second.sock == sock_) {
121 i->second.server->removeSocket(sock_);
122 removeEvent(i->first);
123 WSACloseEvent(i->first);
124 delete sock_;
125 connections.erase(i);
126 return;
127 }
128 }
129 throw rdr::Exception("Socket not registered");
130}
131
Pierre Ossman025326d2018-10-08 16:03:01 +0200132bool SocketManager::getDisable(network::SocketServer* srvr)
133{
134 std::map<HANDLE,ListenInfo>::iterator i;
135 for (i=listeners.begin(); i!=listeners.end(); i++) {
136 if (i->second.server == srvr) {
137 return i->second.disable;
138 }
139 }
140 throw rdr::Exception("Listener not registered");
141}
142
143void SocketManager::setDisable(network::SocketServer* srvr, bool disable)
144{
145 bool found = false;
146 std::map<HANDLE,ListenInfo>::iterator i;
147 for (i=listeners.begin(); i!=listeners.end(); i++) {
148 if (i->second.server == srvr) {
149 i->second.disable = disable;
150 // There might be multiple sockets for the same server, so
151 // continue iterating
152 found = true;
153 }
154 }
155 if (!found)
156 throw rdr::Exception("Listener not registered");
157}
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000158
159int SocketManager::checkTimeouts() {
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000160 int timeout = EventManager::checkTimeouts();
161
162 std::map<HANDLE,ListenInfo>::iterator i;
163 for (i=listeners.begin(); i!=listeners.end(); i++)
164 soonestTimeout(&timeout, i->second.server->checkTimeouts());
165
166 std::list<network::Socket*> shutdownSocks;
167 std::map<HANDLE,ConnInfo>::iterator j, j_next;
168 for (j=connections.begin(); j!=connections.end(); j=j_next) {
169 j_next = j; j_next++;
170 if (j->second.sock->isShutdown())
171 shutdownSocks.push_back(j->second.sock);
172 }
173
174 std::list<network::Socket*>::iterator k;
175 for (k=shutdownSocks.begin(); k!=shutdownSocks.end(); k++)
176 remSocket(*k);
177
178 return timeout;
179}
180
181
182void SocketManager::processEvent(HANDLE event) {
183 if (listeners.count(event)) {
184 ListenInfo li = listeners[event];
185
186 // Accept an incoming connection
187 vlog.debug("accepting incoming connection");
188
189 // What kind of event is this?
190 WSANETWORKEVENTS network_events;
191 WSAEnumNetworkEvents(li.sock->getFd(), event, &network_events);
192 if (network_events.lNetworkEvents & FD_ACCEPT) {
193 network::Socket* new_sock = li.sock->accept();
Pierre Ossman025326d2018-10-08 16:03:01 +0200194 if (new_sock && li.disable) {
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000195 delete new_sock;
196 new_sock = 0;
197 }
198 if (new_sock)
199 addSocket(new_sock, li.server, false);
200 } else if (network_events.lNetworkEvents & FD_CLOSE) {
201 vlog.info("deleting listening socket");
202 remListener(li.sock);
203 } else if (network_events.lNetworkEvents & FD_ADDRESS_LIST_CHANGE) {
Pierre Ossman79f82f92015-03-17 13:44:00 +0100204 li.notifier->processAddressChange();
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000205 requestAddressChangeEvents(li.sock);
206 } else {
207 vlog.error("unknown listener event: %lx", network_events.lNetworkEvents);
208 }
209 } else if (connections.count(event)) {
210 ConnInfo ci = connections[event];
211
212 try {
213 // Process data from an active connection
214
215 // Cancel event notification for this socket
216 if (WSAEventSelect(ci.sock->getFd(), event, 0) == SOCKET_ERROR)
217 throw rdr::SystemException("unable to disable WSAEventSelect:%u", WSAGetLastError());
218
219 // Reset the event object
220 WSAResetEvent(event);
221
222 // Call the socket server to process the event
Pierre Ossmand408ca52016-04-29 14:26:05 +0200223 ci.server->processSocketReadEvent(ci.sock);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000224 if (ci.sock->isShutdown()) {
225 remSocket(ci.sock);
226 return;
227 }
228
229 // Re-instate the required socket event
230 // If the read event is still valid, the event object gets set here
231 if (WSAEventSelect(ci.sock->getFd(), event, FD_READ | FD_CLOSE) == SOCKET_ERROR)
232 throw rdr::SystemException("unable to re-enable WSAEventSelect:%u", WSAGetLastError());
233 } catch (rdr::Exception& e) {
Pierre Ossmanad8609a2012-04-26 09:04:14 +0000234 vlog.error("%s", e.str());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000235 remSocket(ci.sock);
236 }
237 }
238}