blob: 04044823e563ec52d64ff358d5a3ab731a8f5048 [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
Sebastian Zenker042580f2019-01-29 15:48:12 +010070TQTcpServer::~TQTcpServer() = default;
Roger Meier86e89862012-02-10 19:53:20 +000071
Konrad Grochowski16a23a62014-11-13 15:33:38 +010072void TQTcpServer::processIncoming() {
Roger Meier86e89862012-02-10 19:53:20 +000073 while (server_->hasPendingConnections()) {
74 // take ownership of the QTcpSocket; technically it could be deleted
75 // when the QTcpServer is destroyed, but any real app should delete this
76 // class before deleting the QTcpServer that we are using
77 shared_ptr<QTcpSocket> connection(server_->nextPendingConnection());
Roger Meier8b51bc62014-07-24 23:33:33 +020078
Roger Meier86e89862012-02-10 19:53:20 +000079 shared_ptr<TTransport> transport;
80 shared_ptr<TProtocol> iprot;
81 shared_ptr<TProtocol> oprot;
Roger Meier8b51bc62014-07-24 23:33:33 +020082
Roger Meier86e89862012-02-10 19:53:20 +000083 try {
84 transport = shared_ptr<TTransport>(new TQIODeviceTransport(connection));
85 iprot = shared_ptr<TProtocol>(pfact_->getProtocol(transport));
86 oprot = shared_ptr<TProtocol>(pfact_->getProtocol(transport));
Konrad Grochowski16a23a62014-11-13 15:33:38 +010087 } catch (...) {
Roger Meier86e89862012-02-10 19:53:20 +000088 qWarning("[TQTcpServer] Failed to initialize transports/protocols");
89 continue;
90 }
Roger Meier8b51bc62014-07-24 23:33:33 +020091
Konrad Grochowski16a23a62014-11-13 15:33:38 +010092 ctxMap_[connection.get()]
cyy64750162019-02-08 13:40:59 +080093 = std::make_shared<ConnectionContext>(connection, transport, iprot, oprot);
Roger Meier8b51bc62014-07-24 23:33:33 +020094
Roger Meier86e89862012-02-10 19:53:20 +000095 connect(connection.get(), SIGNAL(readyRead()), SLOT(beginDecode()));
Roger Meier8b51bc62014-07-24 23:33:33 +020096
Sebastian Zenkere917a272016-01-18 08:45:52 +010097 connect(connection.get(), SIGNAL(disconnected()), SLOT(socketClosed()));
Roger Meier86e89862012-02-10 19:53:20 +000098 }
99}
100
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100101void TQTcpServer::beginDecode() {
Sebastian Zenker042580f2019-01-29 15:48:12 +0100102 auto* connection(qobject_cast<QTcpSocket*>(sender()));
Roger Meier86e89862012-02-10 19:53:20 +0000103 Q_ASSERT(connection);
104
Roger Meier19a99152012-02-11 19:09:30 +0000105 if (ctxMap_.find(connection) == ctxMap_.end()) {
Roger Meier86e89862012-02-10 19:53:20 +0000106 qWarning("[TQTcpServer] Got data on an unknown QTcpSocket");
107 return;
108 }
Roger Meier8b51bc62014-07-24 23:33:33 +0200109
Roger Meier86e89862012-02-10 19:53:20 +0000110 shared_ptr<ConnectionContext> ctx = ctxMap_[connection];
Roger Meier8b51bc62014-07-24 23:33:33 +0200111
Roger Meier86e89862012-02-10 19:53:20 +0000112 try {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100113 processor_
James E. King, III82ae9572017-08-05 12:23:54 -0400114 ->process(bind(&TQTcpServer::finish, this, ctx, _1),
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100115 ctx->iprot_,
116 ctx->oprot_);
117 } catch (const TTransportException& ex) {
118 qWarning("[TQTcpServer] TTransportException during processing: '%s'", ex.what());
Sebastian Zenkere917a272016-01-18 08:45:52 +0100119 scheduleDeleteConnectionContext(connection);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100120 } catch (...) {
Roger Meier86e89862012-02-10 19:53:20 +0000121 qWarning("[TQTcpServer] Unknown processor exception");
Sebastian Zenkere917a272016-01-18 08:45:52 +0100122 scheduleDeleteConnectionContext(connection);
Roger Meier86e89862012-02-10 19:53:20 +0000123 }
124}
125
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100126void TQTcpServer::socketClosed() {
Sebastian Zenker042580f2019-01-29 15:48:12 +0100127 auto* connection(qobject_cast<QTcpSocket*>(sender()));
Roger Meier86e89862012-02-10 19:53:20 +0000128 Q_ASSERT(connection);
Sebastian Zenkere917a272016-01-18 08:45:52 +0100129 scheduleDeleteConnectionContext(connection);
130}
Roger Meier86e89862012-02-10 19:53:20 +0000131
Sebastian Zenkere917a272016-01-18 08:45:52 +0100132void TQTcpServer::deleteConnectionContext(QTcpSocket* connection) {
133 const ConnectionContextMap::size_type deleted = ctxMap_.erase(connection);
134 if (0 == deleted) {
135 qWarning("[TQTcpServer] Unknown QTcpSocket");
Roger Meier86e89862012-02-10 19:53:20 +0000136 }
Sebastian Zenkere917a272016-01-18 08:45:52 +0100137}
Roger Meier8b51bc62014-07-24 23:33:33 +0200138
Sebastian Zenkere917a272016-01-18 08:45:52 +0100139void TQTcpServer::scheduleDeleteConnectionContext(QTcpSocket* connection) {
140 QMetaObject::invokeMethod(this, "deleteConnectionContext", Qt::QueuedConnection, Q_ARG(QTcpSocket*, connection));
Roger Meier86e89862012-02-10 19:53:20 +0000141}
142
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100143void TQTcpServer::finish(shared_ptr<ConnectionContext> ctx, bool healthy) {
Roger Meier19a99152012-02-11 19:09:30 +0000144 if (!healthy) {
Roger Meier86e89862012-02-10 19:53:20 +0000145 qWarning("[TQTcpServer] Processor failed to process data successfully");
Sebastian Zenkere917a272016-01-18 08:45:52 +0100146 deleteConnectionContext(ctx->connection_.get());
Roger Meier86e89862012-02-10 19:53:20 +0000147 }
148}
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100149}
150}
151} // apache::thrift::async