Remoto - VFS: VFS_tcp_server.cpp Source File
Remoto - VFS
VFS_tcp_server.cpp
Go to the documentation of this file.
1 
2 #include "VFS_tcp_server.h"
3 
4 #include "VFS.h"
5 
6 #include <QFile>
7 #include <QtNetwork/QSslCertificate>
8 #include <QtNetwork/QSslKey>
9 
23 VFSQTcpServer::VFSQTcpServer(QObject *parent, bool ssl)
24 : QTcpServer(parent)
25 , _ssl(ssl)
26 {
27 }
28 
36 // roughly based on:
37 // https://github.com/GuiTeK/Qt-SslServer/blob/master/example/Server/Server/SslServer.cpp
38 
39 void VFSQTcpServer::incomingConnection(qintptr socketDescriptor)
40 {
41  if (_ssl)
42  {
43  QSslSocket *serverSocket = new QSslSocket(this);
44  if (serverSocket->setSocketDescriptor(socketDescriptor))
45  {
46  serverSocket->setProtocol(QSsl::SecureProtocols);
47  serverSocket->setSslConfiguration(_sslConfiguration);
48 
49  connect(serverSocket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
50 
51  addPendingConnection(serverSocket);
52 
53  connect(serverSocket, SIGNAL(encrypted()), this, SLOT(sslReady()));
54  connect(serverSocket, SIGNAL(modeChanged(QSslSocket::SslMode)), this, SLOT(modeChanged(QSslSocket::SslMode)));
55  serverSocket->startServerEncryption();
56  }
57  else
58  { delete serverSocket;
59  VFS::ERROR("Could not set socket descriptor. Aborting.");
60  }
61  }
62  else
63  QTcpServer::incomingConnection(socketDescriptor);
64 }
65 
71 void VFSQTcpServer::setSslConfiguration(QSslConfiguration sslConfiguration)
72 {
73  _sslConfiguration = sslConfiguration;
74 }
75 
81 void VFSQTcpServer::sslErrors(const QList<QSslError> &errors)
82 {
83  for (int i=0;i<errors.size();i++)
84  VFS::ERROR( errors.at(i).errorString(), 0, this->metaObject()->className() );
85 }
86 
92 {
93  //VFS::WARN( "SSL handshake complete...", 0, this->metaObject()->className() );
94 }
95 
103 void VFSQTcpServer::modeChanged(QSslSocket::SslMode mode)
104 {
105  Q_UNUSED(mode);
106 }
107 
145 VFS_tcp_server::VFS_tcp_server(quint16 port, QHostAddress address, bool ssl, QString sslCertPath, QString sslKeyPath)
146 : VFS_node()
147 , _listenAddress(address)
148 , _port(port)
149 , _ssl(ssl)
150 , _sslCertPath(sslCertPath)
151 , _sslKeyPath(sslKeyPath)
152 , _socket(this,ssl)
153 {
154  //connect(this,SIGNAL(mounted()),this,SLOT(listen()));
155  connect(VFS::root(),SIGNAL(initialized()),this,SLOT(listen()));
156 }
157 
159 {
160  _socket.close();
161 }
162 
171 {
172  return true;
173 }
174 
187 {
188  if (_socket.isListening())
189  { VFS::WARN( QString("%1 TCP socket was already listening! Close it first?").arg(className()) );
190  return false;
191  }
192 
193  connect(&_socket, SIGNAL(newConnection()), this, SLOT(createNewConnection()));
194  connect(&_socket, SIGNAL(acceptError(QAbstractSocket::SocketError)), this, SLOT(clientError(QAbstractSocket::SocketError)));
195 
196  if (_ssl)
197  {
198  //connect(&_socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
199 
200  bool c=false,k=false;
201 
202  QFile certFile(_sslCertPath);
203  QFile keyFile(_sslKeyPath);
204 
205  if (!(c = certFile.open(QIODevice::ReadOnly)))
206  VFS::ERROR( QString("Unable to open cert file: '%1'.").arg(_sslCertPath), 0, className() );
207  else
208  VFS::LOG( QString("Reading cert file: '%1'").arg(_sslCertPath), 7, className() );
209 
210  if (!(k = keyFile.open(QIODevice::ReadOnly)))
211  VFS::ERROR( QString("Unable to open key file: '%1'.").arg(_sslKeyPath), 0, className() );
212  else
213  VFS::LOG( QString("Reading key file: '%1'").arg(_sslKeyPath), 7, className() );
214 
215  if (!k || !c)
216  { VFS::ERROR( QString("Will not open port %1").arg(_port) );
217  return false;
218  }
219 
220  QSslCertificate certificate(&certFile, QSsl::Pem);
221  QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem);
222  certFile.close();
223  keyFile.close();
224 
225  //sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
226  _sslConfiguration.setLocalCertificate(certificate);
227  _sslConfiguration.setPrivateKey(sslKey);
228  //_sslConfiguration.setProtocol(QSsl::TlsV1SslV3);
229  _sslConfiguration.setProtocol(QSsl::SecureProtocols);
230 
232  }
233 
234  bool l = _socket.listen( _listenAddress, _port);
235 
236  if (!l)
237  VFS::WARN( QString("%1 could not listen on TCP port %2. Is it already in use?").arg(className()).arg(_port) );
238  else
239  {
240  if (_port == 0)
241  _port = _socket.serverPort();
242  VFS::LOG( QString("%1 listening on TCP port %2 (%3)").arg(className()).arg(_port).arg(_ssl?"secure":"insecure"), 2 );
243  }
244 
245  return l;
246 }
247 
255 {
256  return QString("address: %1\nport: %2\nlistening: %3").arg(_listenAddress.toString()).arg(_port).arg(_socket.isListening()?"true":"false");
257 }
258 
266 {
267  //VFS::WARN( QString("%1 newConnection() should be overridden in a subclass").arg(className()) );
268 
269  while(_socket.hasPendingConnections())
270  {
271  QTcpSocket *s = _socket.nextPendingConnection();
272 
274 
275  connect( client, SIGNAL( disconnected() ),
276  this, SLOT( closeConnection() ) );
277 
278  //moved to newConnection() so it can be overridden.
279  //connect( client, SIGNAL( readyMessage(QByteArray)),
280  // this, SLOT( clientMessage(QByteArray)) );
281 
282  connect( client, SIGNAL( error(QAbstractSocket::SocketError) ),
283  this, SLOT( clientError(QAbstractSocket::SocketError) ) );
284 
285  QHostAddress a = s->peerAddress();
286  QString name = uniqueChildName(a.toString());
287 
288  if (append(name,client))
289  {
290  VFS::LOG( QString("New connection from '%1' to port %2 (%3)\n").arg(client->_address).arg(_port).arg(_ssl?"secure":"insecure"), 8, className() );
291  newConnection(client);
292  }
293  else
294  delete client;
295  }
296 }
297 
304 //FIXME -- add some kind of auth here?
306 {
307  connect( client, SIGNAL( readyMessage(QByteArray)),
308  this, SLOT( clientMessage(QByteArray)) );
309 
310  client->initSSL();
311 
312  /*
313  if (false)
314  {
315  //by default not authorized
316  VFS::ERROR( QString("Client '%1' is not authorized!\n").arg(client->_address) );
317  client->close();
318  }
319  */
320 }
321 
332 VFS_tcp_client *VFS_tcp_server::newClient(QTcpSocket *socket, bool ssl, QSslConfiguration sslConfiguration)
333 {
334  return new VFS_tcp_client( socket, ssl, sslConfiguration);
335 }
336 
337 
345 {
346  VFS_tcp_client *s = dynamic_cast< VFS_tcp_client * >(sender());
347 
348  if (s)
349  {
350  QString n;
351  s->close();
352  remove( s,&n );
353 
354  VFS::LOG( QString("Closing %1 connection '%2'").arg(s->className()).arg(n), 3 );
355 
356  delete s;
357  //s->deleteLater();
358  }
359  else
360  {
361  VFS::WARN( QString("Disconnection, however could not cast sender to VFS_tcp_client.") );
362  }
363 }
364 
373 {
374  VFS::WARN( QString("%1 clientMessage() should be overridden in a subclass").arg(className()) );
375 
376  VFS_tcp_client *s = dynamic_cast< VFS_tcp_client * >(sender());
377 
378  if (s)
379  {
380  VFS::LOG( QString("%1=>%2 read: %3").arg(className()).arg(s->className()).arg( QString(message) ) );
381 
382  //s->close();
383  }
384  else
385  VFS::WARN( QString("%1 clientData() called without client!").arg(className()) );
386 
387 }
388 
394 void VFS_tcp_server::clientError(QAbstractSocket::SocketError error)
395 {
396  if (error != QAbstractSocket::RemoteHostClosedError )
397  {
398  //VFS::ERROR( QString("%1: (%2) %3").arg(className()).arg(error).arg(_socket.errorString()) );
399  //VFS::WARN( QString("(%1) Seems like something should happen here.").arg(className()) );
400  }
401 }
402 
409 {
410  VFS_node::ls(r);
411 }
412 
426 {
428 
429  r->_metadata["address"] = _listenAddress.toString();
430  r->_metadata["port"] = _port;
431 }
432 
433 
VFS_node is the base class from which all other VFS_node classes derive.
Definition: VFS_node.h:143
virtual VFS_node * append(QString name, VFS_node *node, bool containerCheck=true, QString user="server")
Append a VFS_node as a child of this node.
Definition: VFS_node.cpp:1566
virtual void metadata(VFS_request *r)
Fetch the metadata of this node.
Definition: VFS_node.cpp:797
QString uniqueChildName(QString name)
Generate a unique child name.
Definition: VFS_node.cpp:2054
virtual void ls(VFS_request *r)
List the contents of this node.
Definition: VFS_node.cpp:692
QString className()
Return the class name of a node.
Definition: VFS_node.cpp:2039
void remove(bool andDelete)
Remove a child node.
Definition: VFS_node.cpp:1629
The base class for all requests between nodes.
Definition: VFS_node.h:54
QJsonObject _metadata
the request payload
Definition: VFS_node.h:101
QString _address
The address resolved by peerAddress(), or the address to connect to.
void initSSL()
DOCME.
virtual void close()
DOCME.
QString _sslKeyPath
ssl key file path
virtual void read(VFS_request *r)
Read the state of this node, which is the result of ls().
virtual void createNewConnection()
The server has received a new connection request.
virtual QString reportDetails()
Report details of this node.
virtual void clientError(QAbstractSocket::SocketError error)
A socket error has occurred.
virtual bool isContainer()
A server is a container.
QSslConfiguration _sslConfiguration
ssl config built up from below paths
QHostAddress _listenAddress
Address(es) allowed to connect, or 0.0.0.0 if all are allowed.
virtual void newConnection(VFS_tcp_client *c)
Attach the clientMessage handler.
virtual bool listen()
Open the server socket and listen for new connections.
virtual ~VFS_tcp_server()
bool _ssl
Use ssl?
virtual void metadata(VFS_request *r)
Fetch the metadata for this node.
VFSQTcpServer _socket
TCP socket used for connections.
QString _sslCertPath
ssl cert file path
virtual VFS_tcp_client * newClient(QTcpSocket *socket, bool ssl=false, QSslConfiguration sslConfiguration=QSslConfiguration())
Create a new VFS_tcp_client with the new socket.
virtual void clientMessage(QByteArray message)
A message has been received.
quint16 _port
TCP port to listen on, or 0 to find an available one.
VFS_tcp_server(quint16 port=0, QHostAddress address=QHostAddress::Any, bool ssl=false, QString sslCertPath="", QString sslKeyPath="")
Create a VFS_tcp_server node.
virtual void closeConnection()
Close a socket connection.
static VFS * root()
Return the root node of the VFS filesystem.
Definition: VFS.cpp:399
static void LOG(QString message, int level=0, QString user="server")
Send a message to the VFS::_messages VFS_stream.
Definition: VFS.cpp:209
static void ERROR(QString message, int level=0, QString user="server")
Send a message to the VFS::_errors VFS_stream.
Definition: VFS.cpp:307
static void WARN(QString message, int level=0, QString user="server")
Send a message to the VFS::_warnings VFS_stream.
Definition: VFS.cpp:258
void setSslConfiguration(QSslConfiguration sslConfiguration)
Set the SSL configuration.
void incomingConnection(qintptr socketDescriptor)
Handle a new incoming connection.
bool _ssl
Use ssl?
QSslConfiguration _sslConfiguration
The ssl configuration, which will include cert files and ssl mode.
VFSQTcpServer(QObject *parent=nullptr, bool ssl=false)
Create a VFSQTcpServer, which allows to create QSslSocket instances if _ssl is true.
void modeChanged(QSslSocket::SslMode mode)
A slot for when the SSL mode has changed.
void sslErrors(const QList< QSslError > &errors)
One or more ssl errors have occurred.
void sslReady()
SSL is ready, but do nothing.
message(m)
Change the message of an existing arrowMessage.
setter error
Set the error value of this widget.