blob: 99aad071a2c4f77bbdb0fb11be35124d64a482a3 [file] [log] [blame]
Roger Meier7699b402012-04-08 18:18:44 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
Roger Meier86e89862012-02-10 19:53:20 +000019
cyy316723a2019-01-05 16:35:14 +080020#include <functional>
21#include <memory>
22
Roger Meier4285ba22013-06-10 21:17:23 +020023#include <thrift/qt/TQTcpServer.h>
24#include <thrift/qt/TQIODeviceTransport.h>
Roger Meier86e89862012-02-10 19:53:20 +000025
Sebastian Zenkere917a272016-01-18 08:45:52 +010026#include <QMetaType>
Roger Meier86e89862012-02-10 19:53:20 +000027#include <QTcpSocket>
28
Roger Meier49ff8b12012-04-13 09:12:31 +000029#include <thrift/protocol/TProtocol.h>
30#include <thrift/async/TAsyncProcessor.h>
Roger Meier86e89862012-02-10 19:53:20 +000031
Roger Meier86e89862012-02-10 19:53:20 +000032using apache::thrift::protocol::TProtocol;
33using apache::thrift::protocol::TProtocolFactory;
34using apache::thrift::transport::TTransport;
35using apache::thrift::transport::TTransportException;
36using apache::thrift::transport::TQIODeviceTransport;
cyy316723a2019-01-05 16:35:14 +080037using std::bind;
38using std::function;
39using std::placeholders::_1;
40using std::shared_ptr;
Roger Meier86e89862012-02-10 19:53:20 +000041
42QT_USE_NAMESPACE
43
Konrad Grochowski16a23a62014-11-13 15:33:38 +010044namespace apache {
45namespace thrift {
46namespace async {
Roger Meier86e89862012-02-10 19:53:20 +000047
48struct TQTcpServer::ConnectionContext {
49 shared_ptr<QTcpSocket> connection_;
50 shared_ptr<TTransport> transport_;
51 shared_ptr<TProtocol> iprot_;
52 shared_ptr<TProtocol> oprot_;
53
54 explicit ConnectionContext(shared_ptr<QTcpSocket> connection,
55 shared_ptr<TTransport> transport,
56 shared_ptr<TProtocol> iprot,
57 shared_ptr<TProtocol> oprot)
Konrad Grochowski16a23a62014-11-13 15:33:38 +010058 : connection_(connection), transport_(transport), iprot_(iprot), oprot_(oprot) {}
Roger Meier86e89862012-02-10 19:53:20 +000059};
60
61TQTcpServer::TQTcpServer(shared_ptr<QTcpServer> server,
62 shared_ptr<TAsyncProcessor> processor,
63 shared_ptr<TProtocolFactory> pfact,
64 QObject* parent)
Konrad Grochowski16a23a62014-11-13 15:33:38 +010065 : QObject(parent), server_(server), processor_(processor), pfact_(pfact) {
Sebastian Zenkere917a272016-01-18 08:45:52 +010066 qRegisterMetaType<QTcpSocket*>("QTcpSocket*");
Roger Meier86e89862012-02-10 19:53:20 +000067 connect(server.get(), SIGNAL(newConnection()), SLOT(processIncoming()));
68}
69
Konrad Grochowski16a23a62014-11-13 15:33:38 +010070TQTcpServer::~TQTcpServer() {
Roger Meier86e89862012-02-10 19:53:20 +000071}
72
Konrad Grochowski16a23a62014-11-13 15:33:38 +010073void TQTcpServer::processIncoming() {
Roger Meier86e89862012-02-10 19:53:20 +000074 while (server_->hasPendingConnections()) {
75 // take ownership of the QTcpSocket; technically it could be deleted
76 // when the QTcpServer is destroyed, but any real app should delete this
77 // class before deleting the QTcpServer that we are using
78 shared_ptr<QTcpSocket> connection(server_->nextPendingConnection());
Roger Meier8b51bc62014-07-24 23:33:33 +020079
Roger Meier86e89862012-02-10 19:53:20 +000080 shared_ptr<TTransport> transport;
81 shared_ptr<TProtocol> iprot;
82 shared_ptr<TProtocol> oprot;
Roger Meier8b51bc62014-07-24 23:33:33 +020083
Roger Meier86e89862012-02-10 19:53:20 +000084 try {
85 transport = shared_ptr<TTransport>(new TQIODeviceTransport(connection));
86 iprot = shared_ptr<TProtocol>(pfact_->getProtocol(transport));
87 oprot = shared_ptr<TProtocol>(pfact_->getProtocol(transport));
Konrad Grochowski16a23a62014-11-13 15:33:38 +010088 } catch (...) {
Roger Meier86e89862012-02-10 19:53:20 +000089 qWarning("[TQTcpServer] Failed to initialize transports/protocols");
90 continue;
91 }
Roger Meier8b51bc62014-07-24 23:33:33 +020092
Konrad Grochowski16a23a62014-11-13 15:33:38 +010093 ctxMap_[connection.get()]
94 = shared_ptr<ConnectionContext>(new ConnectionContext(connection, transport, iprot, oprot));
Roger Meier8b51bc62014-07-24 23:33:33 +020095
Roger Meier86e89862012-02-10 19:53:20 +000096 connect(connection.get(), SIGNAL(readyRead()), SLOT(beginDecode()));
Roger Meier8b51bc62014-07-24 23:33:33 +020097
Sebastian Zenkere917a272016-01-18 08:45:52 +010098 connect(connection.get(), SIGNAL(disconnected()), SLOT(socketClosed()));
Roger Meier86e89862012-02-10 19:53:20 +000099 }
100}
101
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100102void TQTcpServer::beginDecode() {
Roger Meier86e89862012-02-10 19:53:20 +0000103 QTcpSocket* connection(qobject_cast<QTcpSocket*>(sender()));
104 Q_ASSERT(connection);
105
Roger Meier19a99152012-02-11 19:09:30 +0000106 if (ctxMap_.find(connection) == ctxMap_.end()) {
Roger Meier86e89862012-02-10 19:53:20 +0000107 qWarning("[TQTcpServer] Got data on an unknown QTcpSocket");
108 return;
109 }
Roger Meier8b51bc62014-07-24 23:33:33 +0200110
Roger Meier86e89862012-02-10 19:53:20 +0000111 shared_ptr<ConnectionContext> ctx = ctxMap_[connection];
Roger Meier8b51bc62014-07-24 23:33:33 +0200112
Roger Meier86e89862012-02-10 19:53:20 +0000113 try {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100114 processor_
James E. King, III82ae9572017-08-05 12:23:54 -0400115 ->process(bind(&TQTcpServer::finish, this, ctx, _1),
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100116 ctx->iprot_,
117 ctx->oprot_);
118 } catch (const TTransportException& ex) {
119 qWarning("[TQTcpServer] TTransportException during processing: '%s'", ex.what());
Sebastian Zenkere917a272016-01-18 08:45:52 +0100120 scheduleDeleteConnectionContext(connection);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100121 } catch (...) {
Roger Meier86e89862012-02-10 19:53:20 +0000122 qWarning("[TQTcpServer] Unknown processor exception");
Sebastian Zenkere917a272016-01-18 08:45:52 +0100123 scheduleDeleteConnectionContext(connection);
Roger Meier86e89862012-02-10 19:53:20 +0000124 }
125}
126
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100127void TQTcpServer::socketClosed() {
Roger Meier86e89862012-02-10 19:53:20 +0000128 QTcpSocket* connection(qobject_cast<QTcpSocket*>(sender()));
129 Q_ASSERT(connection);
Sebastian Zenkere917a272016-01-18 08:45:52 +0100130 scheduleDeleteConnectionContext(connection);
131}
Roger Meier86e89862012-02-10 19:53:20 +0000132
Sebastian Zenkere917a272016-01-18 08:45:52 +0100133void TQTcpServer::deleteConnectionContext(QTcpSocket* connection) {
134 const ConnectionContextMap::size_type deleted = ctxMap_.erase(connection);
135 if (0 == deleted) {
136 qWarning("[TQTcpServer] Unknown QTcpSocket");
Roger Meier86e89862012-02-10 19:53:20 +0000137 }
Sebastian Zenkere917a272016-01-18 08:45:52 +0100138}
Roger Meier8b51bc62014-07-24 23:33:33 +0200139
Sebastian Zenkere917a272016-01-18 08:45:52 +0100140void TQTcpServer::scheduleDeleteConnectionContext(QTcpSocket* connection) {
141 QMetaObject::invokeMethod(this, "deleteConnectionContext", Qt::QueuedConnection, Q_ARG(QTcpSocket*, connection));
Roger Meier86e89862012-02-10 19:53:20 +0000142}
143
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100144void TQTcpServer::finish(shared_ptr<ConnectionContext> ctx, bool healthy) {
Roger Meier19a99152012-02-11 19:09:30 +0000145 if (!healthy) {
Roger Meier86e89862012-02-10 19:53:20 +0000146 qWarning("[TQTcpServer] Processor failed to process data successfully");
Sebastian Zenkere917a272016-01-18 08:45:52 +0100147 deleteConnectionContext(ctx->connection_.get());
Roger Meier86e89862012-02-10 19:53:20 +0000148 }
149}
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100150}
151}
152} // apache::thrift::async