blob: 9a0dab4c82d79e9ec38a5a6c68d7209948fb249f [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)
46 vlog.error("Unable to track address changes", err);
47 }
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_;
73 vlog.error(e.str());
74 throw;
75 }
76
77 ListenInfo li;
78 li.sock = sock_;
79 li.server = srvr;
80 li.notifier = acn;
81 listeners[event] = li;
82}
83
84void SocketManager::remListener(network::SocketListener* sock) {
85 std::map<HANDLE,ListenInfo>::iterator i;
86 for (i=listeners.begin(); i!=listeners.end(); i++) {
87 if (i->second.sock == sock) {
88 removeEvent(i->first);
89 WSACloseEvent(i->first);
90 delete sock;
91 listeners.erase(i);
92 return;
93 }
94 }
95 throw rdr::Exception("Listener not registered");
96}
97
98
99void SocketManager::addSocket(network::Socket* sock_, network::SocketServer* srvr, bool outgoing) {
100 WSAEVENT event = WSACreateEvent();
101 if (!event || !addEvent(event, this) ||
102 (WSAEventSelect(sock_->getFd(), event, FD_READ | FD_CLOSE) == SOCKET_ERROR)) {
103 if (event)
104 WSACloseEvent(event);
105 delete sock_;
106 vlog.error("Unable to add connection");
107 return;
108 }
109 ConnInfo ci;
110 ci.sock = sock_;
111 ci.server = srvr;
112 connections[event] = ci;
113 srvr->addSocket(sock_, outgoing);
114}
115
116void SocketManager::remSocket(network::Socket* sock_) {
117 std::map<HANDLE,ConnInfo>::iterator i;
118 for (i=connections.begin(); i!=connections.end(); i++) {
119 if (i->second.sock == sock_) {
120 i->second.server->removeSocket(sock_);
121 removeEvent(i->first);
122 WSACloseEvent(i->first);
123 delete sock_;
124 connections.erase(i);
125 return;
126 }
127 }
128 throw rdr::Exception("Socket not registered");
129}
130
131
132int SocketManager::checkTimeouts() {
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000133 int timeout = EventManager::checkTimeouts();
134
135 std::map<HANDLE,ListenInfo>::iterator i;
136 for (i=listeners.begin(); i!=listeners.end(); i++)
137 soonestTimeout(&timeout, i->second.server->checkTimeouts());
138
139 std::list<network::Socket*> shutdownSocks;
140 std::map<HANDLE,ConnInfo>::iterator j, j_next;
141 for (j=connections.begin(); j!=connections.end(); j=j_next) {
142 j_next = j; j_next++;
143 if (j->second.sock->isShutdown())
144 shutdownSocks.push_back(j->second.sock);
145 }
146
147 std::list<network::Socket*>::iterator k;
148 for (k=shutdownSocks.begin(); k!=shutdownSocks.end(); k++)
149 remSocket(*k);
150
151 return timeout;
152}
153
154
155void SocketManager::processEvent(HANDLE event) {
156 if (listeners.count(event)) {
157 ListenInfo li = listeners[event];
158
159 // Accept an incoming connection
160 vlog.debug("accepting incoming connection");
161
162 // What kind of event is this?
163 WSANETWORKEVENTS network_events;
164 WSAEnumNetworkEvents(li.sock->getFd(), event, &network_events);
165 if (network_events.lNetworkEvents & FD_ACCEPT) {
166 network::Socket* new_sock = li.sock->accept();
167 if (new_sock && li.server->getDisable()) {
168 delete new_sock;
169 new_sock = 0;
170 }
171 if (new_sock)
172 addSocket(new_sock, li.server, false);
173 } else if (network_events.lNetworkEvents & FD_CLOSE) {
174 vlog.info("deleting listening socket");
175 remListener(li.sock);
176 } else if (network_events.lNetworkEvents & FD_ADDRESS_LIST_CHANGE) {
177 li.notifier->processAddressChange(li.sock);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000178 requestAddressChangeEvents(li.sock);
179 } else {
180 vlog.error("unknown listener event: %lx", network_events.lNetworkEvents);
181 }
182 } else if (connections.count(event)) {
183 ConnInfo ci = connections[event];
184
185 try {
186 // Process data from an active connection
187
188 // Cancel event notification for this socket
189 if (WSAEventSelect(ci.sock->getFd(), event, 0) == SOCKET_ERROR)
190 throw rdr::SystemException("unable to disable WSAEventSelect:%u", WSAGetLastError());
191
192 // Reset the event object
193 WSAResetEvent(event);
194
195 // Call the socket server to process the event
196 ci.server->processSocketEvent(ci.sock);
197 if (ci.sock->isShutdown()) {
198 remSocket(ci.sock);
199 return;
200 }
201
202 // Re-instate the required socket event
203 // If the read event is still valid, the event object gets set here
204 if (WSAEventSelect(ci.sock->getFd(), event, FD_READ | FD_CLOSE) == SOCKET_ERROR)
205 throw rdr::SystemException("unable to re-enable WSAEventSelect:%u", WSAGetLastError());
206 } catch (rdr::Exception& e) {
207 vlog.error(e.str());
208 remSocket(ci.sock);
209 }
210 }
211}