blob: 1d52bc86057f7cbd2796f2ad6b2d464657804188 [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
41static requestAddressChangeEvents(network::SocketListener* sock_) {
42 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() {
133 network::SocketServer* server = 0;
134 int timeout = EventManager::checkTimeouts();
135
136 std::map<HANDLE,ListenInfo>::iterator i;
137 for (i=listeners.begin(); i!=listeners.end(); i++)
138 soonestTimeout(&timeout, i->second.server->checkTimeouts());
139
140 std::list<network::Socket*> shutdownSocks;
141 std::map<HANDLE,ConnInfo>::iterator j, j_next;
142 for (j=connections.begin(); j!=connections.end(); j=j_next) {
143 j_next = j; j_next++;
144 if (j->second.sock->isShutdown())
145 shutdownSocks.push_back(j->second.sock);
146 }
147
148 std::list<network::Socket*>::iterator k;
149 for (k=shutdownSocks.begin(); k!=shutdownSocks.end(); k++)
150 remSocket(*k);
151
152 return timeout;
153}
154
155
156void SocketManager::processEvent(HANDLE event) {
157 if (listeners.count(event)) {
158 ListenInfo li = listeners[event];
159
160 // Accept an incoming connection
161 vlog.debug("accepting incoming connection");
162
163 // What kind of event is this?
164 WSANETWORKEVENTS network_events;
165 WSAEnumNetworkEvents(li.sock->getFd(), event, &network_events);
166 if (network_events.lNetworkEvents & FD_ACCEPT) {
167 network::Socket* new_sock = li.sock->accept();
168 if (new_sock && li.server->getDisable()) {
169 delete new_sock;
170 new_sock = 0;
171 }
172 if (new_sock)
173 addSocket(new_sock, li.server, false);
174 } else if (network_events.lNetworkEvents & FD_CLOSE) {
175 vlog.info("deleting listening socket");
176 remListener(li.sock);
177 } else if (network_events.lNetworkEvents & FD_ADDRESS_LIST_CHANGE) {
178 li.notifier->processAddressChange(li.sock);
179 DWORD dummy = 0;
180 requestAddressChangeEvents(li.sock);
181 } else {
182 vlog.error("unknown listener event: %lx", network_events.lNetworkEvents);
183 }
184 } else if (connections.count(event)) {
185 ConnInfo ci = connections[event];
186
187 try {
188 // Process data from an active connection
189
190 // Cancel event notification for this socket
191 if (WSAEventSelect(ci.sock->getFd(), event, 0) == SOCKET_ERROR)
192 throw rdr::SystemException("unable to disable WSAEventSelect:%u", WSAGetLastError());
193
194 // Reset the event object
195 WSAResetEvent(event);
196
197 // Call the socket server to process the event
198 ci.server->processSocketEvent(ci.sock);
199 if (ci.sock->isShutdown()) {
200 remSocket(ci.sock);
201 return;
202 }
203
204 // Re-instate the required socket event
205 // If the read event is still valid, the event object gets set here
206 if (WSAEventSelect(ci.sock->getFd(), event, FD_READ | FD_CLOSE) == SOCKET_ERROR)
207 throw rdr::SystemException("unable to re-enable WSAEventSelect:%u", WSAGetLastError());
208 } catch (rdr::Exception& e) {
209 vlog.error(e.str());
210 remSocket(ci.sock);
211 }
212 }
213}