blob: 9dd8bfe13255393097dfd26f51804ad3b78b6360 [file] [log] [blame]
Pierre Ossman559e8b82018-05-04 12:44:31 +02001/* 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#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
22
23#ifdef WIN32
24//#include <io.h>
25#include <winsock2.h>
26#include <ws2tcpip.h>
27#define errorNumber WSAGetLastError()
28#else
29#define errorNumber errno
30#define closesocket close
31#include <sys/socket.h>
32#endif
33
34#include <unistd.h>
35#include <signal.h>
36#include <fcntl.h>
37#include <errno.h>
38
39#include <network/Socket.h>
40
41using namespace network;
42
43// -=- Socket initialisation
44static bool socketsInitialised = false;
45void network::initSockets() {
46 if (socketsInitialised)
47 return;
48#ifdef WIN32
49 WORD requiredVersion = MAKEWORD(2,0);
50 WSADATA initResult;
51
52 if (WSAStartup(requiredVersion, &initResult) != 0)
53 throw SocketException("unable to initialise Winsock2", errorNumber);
54#else
55 signal(SIGPIPE, SIG_IGN);
56#endif
57 socketsInitialised = true;
58}
59
60bool network::isSocketListening(int sock)
61{
62 int listening = 0;
63 socklen_t listening_size = sizeof(listening);
64 if (getsockopt(sock, SOL_SOCKET, SO_ACCEPTCONN,
65 (char *)&listening, &listening_size) < 0)
66 return false;
67 return listening != 0;
68}
69
70Socket::Socket(int fd)
71 : instream(0), outstream(0),
72 isShutdown_(false), queryConnection(false)
73{
74 initSockets();
75 setFd(fd);
76}
77
78Socket::Socket()
79 : instream(0), outstream(0),
80 isShutdown_(false), queryConnection(false)
81{
82 initSockets();
83}
84
85Socket::~Socket()
86{
87 if (instream && outstream)
88 closesocket(getFd());
89 delete instream;
90 delete outstream;
91}
92
93// if shutdown() is overridden then the override MUST call on to here
94void Socket::shutdown()
95{
96 isShutdown_ = true;
97 ::shutdown(getFd(), 2);
98}
99
100bool Socket::isShutdown() const
101{
102 return isShutdown_;
103}
104
105// Was there a "?" in the ConnectionFilter used to accept this Socket?
106void Socket::setRequiresQuery()
107{
108 queryConnection = true;
109}
110
111bool Socket::requiresQuery() const
112{
113 return queryConnection;
114}
115
116void Socket::setFd(int fd)
117{
118#ifndef WIN32
119 // - By default, close the socket on exec()
120 fcntl(fd, F_SETFD, FD_CLOEXEC);
121#endif
122
123 instream = new rdr::FdInStream(fd);
124 outstream = new rdr::FdOutStream(fd);
125 isShutdown_ = false;
126}
127
128SocketListener::SocketListener(int fd)
129 : fd(fd), filter(0)
130{
131 initSockets();
132}
133
134SocketListener::SocketListener()
135 : fd(-1), filter(0)
136{
137 initSockets();
138}
139
140SocketListener::~SocketListener()
141{
142 if (fd != -1)
143 closesocket(fd);
144}
145
146void SocketListener::shutdown()
147{
148#ifdef WIN32
149 closesocket(fd);
150 fd = -1;
151#else
152 ::shutdown(fd, 2);
153#endif
154}
155
156Socket* SocketListener::accept() {
157 int new_sock = -1;
158
159 // Accept an incoming connection
160 if ((new_sock = ::accept(fd, 0, 0)) < 0)
161 throw SocketException("unable to accept new connection", errorNumber);
162
163 // Create the socket object & check connection is allowed
164 Socket* s = createSocket(new_sock);
165 if (filter && !filter->verifyConnection(s)) {
166 delete s;
167 return NULL;
168 }
169
170 return s;
171}
172
173void SocketListener::listen(int sock)
174{
175 // - Set it to be a listening socket
176 if (::listen(sock, 5) < 0) {
177 int e = errorNumber;
178 closesocket(sock);
179 throw SocketException("unable to set socket to listening mode", e);
180 }
181
182 fd = sock;
183}