Commit adba2ec8 authored by James Sedgwick's avatar James Sedgwick Committed by Praveen Kumar Ramakrishnan

telnet server

Summary: similar to https://github.com/netty/netty/tree/master/example/src/main/java/io/netty/example/telnet

Test Plan:
fbconfig folly/wangle/example/telnet; fbmake dbg
_bin/folly/wangle/example/telnet_server --port=8080
telnet localhost 8080

Still a couple sharp edges:
* No easy way to wait for ServerBootstrap termination.
* Pipelines always have to call attachReadCallback
* a bunch of missing methods in pipeline still, like channelActive

Reviewed By: hans@fb.com

Subscribers: doug, fugalh, folly-diffs@, jsedgwick, yfeldblum, chalfant

FB internal diff: D1959172

Signature: t1:1959172:1427993978:463f237036996451187e3ef3983cf2b4e89685ef
parent 45e22567
...@@ -32,7 +32,8 @@ typedef ClientBootstrap<BytesPipeline> TestClient; ...@@ -32,7 +32,8 @@ typedef ClientBootstrap<BytesPipeline> TestClient;
class TestClientPipelineFactory : public PipelineFactory<BytesPipeline> { class TestClientPipelineFactory : public PipelineFactory<BytesPipeline> {
public: public:
BytesPipeline* newPipeline(std::shared_ptr<AsyncSocket> sock) { std::unique_ptr<BytesPipeline, folly::DelayedDestruction::Destructor>
newPipeline(std::shared_ptr<AsyncSocket> sock) {
CHECK(sock->good()); CHECK(sock->good());
// We probably aren't connected immedately, check after a small delay // We probably aren't connected immedately, check after a small delay
...@@ -45,9 +46,12 @@ class TestClientPipelineFactory : public PipelineFactory<BytesPipeline> { ...@@ -45,9 +46,12 @@ class TestClientPipelineFactory : public PipelineFactory<BytesPipeline> {
class TestPipelineFactory : public PipelineFactory<BytesPipeline> { class TestPipelineFactory : public PipelineFactory<BytesPipeline> {
public: public:
BytesPipeline* newPipeline(std::shared_ptr<AsyncSocket> sock) { std::unique_ptr<BytesPipeline, folly::DelayedDestruction::Destructor> newPipeline(
std::shared_ptr<AsyncSocket> sock) {
pipelines++; pipelines++;
return new BytesPipeline(); return std::unique_ptr<BytesPipeline, folly::DelayedDestruction::Destructor>(
new BytesPipeline());
} }
std::atomic<int> pipelines{0}; std::atomic<int> pipelines{0};
}; };
...@@ -279,8 +283,13 @@ template <typename HandlerPipeline> ...@@ -279,8 +283,13 @@ template <typename HandlerPipeline>
class TestHandlerPipelineFactory class TestHandlerPipelineFactory
: public PipelineFactory<ServerBootstrap<BytesPipeline>::AcceptPipeline> { : public PipelineFactory<ServerBootstrap<BytesPipeline>::AcceptPipeline> {
public: public:
ServerBootstrap<BytesPipeline>::AcceptPipeline* newPipeline(std::shared_ptr<AsyncSocket>) { std::unique_ptr<ServerBootstrap<BytesPipeline>::AcceptPipeline,
auto pipeline = new ServerBootstrap<BytesPipeline>::AcceptPipeline; folly::DelayedDestruction::Destructor>
newPipeline(std::shared_ptr<AsyncSocket>) {
std::unique_ptr<ServerBootstrap<BytesPipeline>::AcceptPipeline,
folly::DelayedDestruction::Destructor> pipeline(
new ServerBootstrap<BytesPipeline>::AcceptPipeline);
pipeline->addBack(HandlerPipeline()); pipeline->addBack(HandlerPipeline());
return pipeline; return pipeline;
} }
......
...@@ -34,10 +34,10 @@ class ClientBootstrap { ...@@ -34,10 +34,10 @@ class ClientBootstrap {
} }
ClientBootstrap* connect(SocketAddress address) { ClientBootstrap* connect(SocketAddress address) {
DCHECK(pipelineFactory_); DCHECK(pipelineFactory_);
pipeline_.reset( pipeline_=
pipelineFactory_->newPipeline( pipelineFactory_->newPipeline(
AsyncSocket::newSocket(EventBaseManager::get()->getEventBase(), address) AsyncSocket::newSocket(
)); EventBaseManager::get()->getEventBase(), address));
return this; return this;
} }
......
...@@ -32,27 +32,35 @@ class ServerAcceptor ...@@ -32,27 +32,35 @@ class ServerAcceptor
typedef std::unique_ptr<Pipeline, typedef std::unique_ptr<Pipeline,
folly::DelayedDestruction::Destructor> PipelinePtr; folly::DelayedDestruction::Destructor> PipelinePtr;
class ServerConnection : public wangle::ManagedConnection { class ServerConnection : public wangle::ManagedConnection,
public wangle::PipelineManager {
public: public:
explicit ServerConnection(PipelinePtr pipeline) explicit ServerConnection(PipelinePtr pipeline)
: pipeline_(std::move(pipeline)) {} : pipeline_(std::move(pipeline)) {
pipeline_->setPipelineManager(this);
~ServerConnection() {
} }
void timeoutExpired() noexcept { ~ServerConnection() {}
void timeoutExpired() noexcept override {
} }
void describe(std::ostream& os) const {} void describe(std::ostream& os) const override {}
bool isBusy() const { bool isBusy() const override {
return false; return false;
} }
void notifyPendingShutdown() {} void notifyPendingShutdown() override {}
void closeWhenIdle() {} void closeWhenIdle() override {}
void dropConnection() { void dropConnection() override {
delete this; delete this;
} }
void dumpConnectionState(uint8_t loglevel) {} void dumpConnectionState(uint8_t loglevel) override {}
void deletePipeline(wangle::PipelineBase* p) override {
CHECK(p == pipeline_.get());
delete this;
}
private: private:
PipelinePtr pipeline_; PipelinePtr pipeline_;
}; };
...@@ -178,8 +186,11 @@ class DefaultAcceptPipelineFactory ...@@ -178,8 +186,11 @@ class DefaultAcceptPipelineFactory
typedef wangle::Pipeline<void*> AcceptPipeline; typedef wangle::Pipeline<void*> AcceptPipeline;
public: public:
AcceptPipeline* newPipeline(std::shared_ptr<AsyncSocket>) { std::unique_ptr<AcceptPipeline, folly::DelayedDestruction::Destructor>
return new AcceptPipeline; newPipeline(std::shared_ptr<AsyncSocket>) {
return std::unique_ptr<AcceptPipeline, folly::DelayedDestruction::Destructor>
(new AcceptPipeline);
} }
}; };
......
...@@ -284,6 +284,13 @@ class ServerBootstrap { ...@@ -284,6 +284,13 @@ class ServerBootstrap {
} }
sockets_->clear(); sockets_->clear();
} }
if (!stopped_) {
stopped_ = true;
// stopBaton_ may be null if ServerBootstrap has been std::move'd
if (stopBaton_) {
stopBaton_->post();
}
}
} }
void join() { void join() {
...@@ -295,6 +302,13 @@ class ServerBootstrap { ...@@ -295,6 +302,13 @@ class ServerBootstrap {
} }
} }
void waitForStop() {
if (!stopped_) {
CHECK(stopBaton_);
stopBaton_->wait();
}
}
/* /*
* Get the list of listening sockets * Get the list of listening sockets
*/ */
...@@ -328,6 +342,10 @@ class ServerBootstrap { ...@@ -328,6 +342,10 @@ class ServerBootstrap {
std::make_shared<DefaultAcceptPipelineFactory>()}; std::make_shared<DefaultAcceptPipelineFactory>()};
std::shared_ptr<ServerSocketFactory> socketFactory_{ std::shared_ptr<ServerSocketFactory> socketFactory_{
std::make_shared<AsyncServerSocketFactory>()}; std::make_shared<AsyncServerSocketFactory>()};
std::unique_ptr<folly::Baton<>> stopBaton_{
folly::make_unique<folly::Baton<>>()};
bool stopped_{false};
}; };
} // namespace } // namespace
...@@ -94,6 +94,7 @@ class AsyncSocketHandler ...@@ -94,6 +94,7 @@ class AsyncSocketHandler
detachReadCallback(); detachReadCallback();
socket_->closeNow(); socket_->closeNow();
} }
ctx->getPipeline()->deletePipeline();
return folly::makeFuture(); return folly::makeFuture();
} }
......
...@@ -201,6 +201,10 @@ class ContextImpl ...@@ -201,6 +201,10 @@ class ContextImpl
} }
} }
PipelineBase* getPipeline() override {
return this->pipeline_;
}
std::shared_ptr<AsyncTransport> getTransport() override { std::shared_ptr<AsyncTransport> getTransport() override {
return this->pipeline_->getTransport(); return this->pipeline_->getTransport();
} }
...@@ -306,6 +310,10 @@ class InboundContextImpl ...@@ -306,6 +310,10 @@ class InboundContextImpl
} }
} }
PipelineBase* getPipeline() override {
return this->pipeline_;
}
std::shared_ptr<AsyncTransport> getTransport() override { std::shared_ptr<AsyncTransport> getTransport() override {
return this->pipeline_->getTransport(); return this->pipeline_->getTransport();
} }
...@@ -375,6 +383,10 @@ class OutboundContextImpl ...@@ -375,6 +383,10 @@ class OutboundContextImpl
} }
} }
PipelineBase* getPipeline() override {
return this->pipeline_;
}
std::shared_ptr<AsyncTransport> getTransport() override { std::shared_ptr<AsyncTransport> getTransport() override {
return this->pipeline_->getTransport(); return this->pipeline_->getTransport();
} }
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
namespace folly { namespace wangle { namespace folly { namespace wangle {
class PipelineBase;
template <class In, class Out> template <class In, class Out>
class HandlerContext { class HandlerContext {
public: public:
...@@ -34,6 +36,8 @@ class HandlerContext { ...@@ -34,6 +36,8 @@ class HandlerContext {
virtual Future<void> fireWrite(Out msg) = 0; virtual Future<void> fireWrite(Out msg) = 0;
virtual Future<void> fireClose() = 0; virtual Future<void> fireClose() = 0;
virtual PipelineBase* getPipeline() = 0;
virtual std::shared_ptr<AsyncTransport> getTransport() = 0; virtual std::shared_ptr<AsyncTransport> getTransport() = 0;
virtual void setWriteFlags(WriteFlags flags) = 0; virtual void setWriteFlags(WriteFlags flags) = 0;
...@@ -64,6 +68,8 @@ class InboundHandlerContext { ...@@ -64,6 +68,8 @@ class InboundHandlerContext {
virtual void fireReadEOF() = 0; virtual void fireReadEOF() = 0;
virtual void fireReadException(exception_wrapper e) = 0; virtual void fireReadException(exception_wrapper e) = 0;
virtual PipelineBase* getPipeline() = 0;
virtual std::shared_ptr<AsyncTransport> getTransport() = 0; virtual std::shared_ptr<AsyncTransport> getTransport() = 0;
// TODO Need get/set writeFlags, readBufferSettings? Probably not. // TODO Need get/set writeFlags, readBufferSettings? Probably not.
...@@ -79,6 +85,8 @@ class OutboundHandlerContext { ...@@ -79,6 +85,8 @@ class OutboundHandlerContext {
virtual Future<void> fireWrite(Out msg) = 0; virtual Future<void> fireWrite(Out msg) = 0;
virtual Future<void> fireClose() = 0; virtual Future<void> fireClose() = 0;
virtual PipelineBase* getPipeline() = 0;
virtual std::shared_ptr<AsyncTransport> getTransport() = 0; virtual std::shared_ptr<AsyncTransport> getTransport() = 0;
}; };
......
...@@ -25,6 +25,28 @@ ...@@ -25,6 +25,28 @@
namespace folly { namespace wangle { namespace folly { namespace wangle {
class PipelineManager {
public:
virtual ~PipelineManager() {}
virtual void deletePipeline(PipelineBase* pipeline) = 0;
};
class PipelineBase {
public:
void setPipelineManager(PipelineManager* manager) {
manager_ = manager;
}
void deletePipeline() {
if (manager_) {
manager_->deletePipeline(this);
}
}
private:
PipelineManager* manager_{nullptr};
};
struct Nothing{}; struct Nothing{};
/* /*
...@@ -36,7 +58,7 @@ struct Nothing{}; ...@@ -36,7 +58,7 @@ struct Nothing{};
* If W is Nothing, write() and close() will be disabled. * If W is Nothing, write() and close() will be disabled.
*/ */
template <class R, class W = Nothing> template <class R, class W = Nothing>
class Pipeline : public DelayedDestruction { class Pipeline : public PipelineBase, public DelayedDestruction {
public: public:
Pipeline(); Pipeline();
~Pipeline(); ~Pipeline();
...@@ -137,7 +159,9 @@ class AsyncSocket; ...@@ -137,7 +159,9 @@ class AsyncSocket;
template <typename Pipeline> template <typename Pipeline>
class PipelineFactory { class PipelineFactory {
public: public:
virtual Pipeline* newPipeline(std::shared_ptr<AsyncSocket>) = 0; virtual std::unique_ptr<Pipeline, folly::DelayedDestruction::Destructor>
newPipeline(std::shared_ptr<AsyncSocket>) = 0;
virtual ~PipelineFactory() {} virtual ~PipelineFactory() {}
}; };
......
...@@ -23,15 +23,14 @@ namespace folly { namespace wangle { ...@@ -23,15 +23,14 @@ namespace folly { namespace wangle {
/* /*
* StringCodec converts a pipeline from IOBufs to std::strings. * StringCodec converts a pipeline from IOBufs to std::strings.
*/ */
class StringCodec : public Handler<IOBufQueue&, std::string, class StringCodec : public Handler<std::unique_ptr<IOBuf>, std::string,
std::string, std::unique_ptr<IOBuf>> { std::string, std::unique_ptr<IOBuf>> {
public: public:
typedef typename Handler< typedef typename Handler<
IOBufQueue&, std::string, std::unique_ptr<IOBuf>, std::string,
std::string, std::unique_ptr<IOBuf>>::Context Context; std::string, std::unique_ptr<IOBuf>>::Context Context;
void read(Context* ctx, IOBufQueue& q) override { void read(Context* ctx, std::unique_ptr<IOBuf> buf) override {
auto buf = q.pop_front();
buf->coalesce(); buf->coalesce();
std::string data((const char*)buf->data(), buf->length()); std::string data((const char*)buf->data(), buf->length());
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <folly/wangle/codec/StringCodec.h> #include <folly/wangle/codec/StringCodec.h>
#include <folly/wangle/codec/ByteToMessageCodec.h>
#include <folly/wangle/service/ClientDispatcher.h> #include <folly/wangle/service/ClientDispatcher.h>
#include <folly/wangle/service/ServerDispatcher.h> #include <folly/wangle/service/ServerDispatcher.h>
#include <folly/wangle/service/Service.h> #include <folly/wangle/service/Service.h>
...@@ -26,6 +27,14 @@ using namespace wangle; ...@@ -26,6 +27,14 @@ using namespace wangle;
typedef Pipeline<IOBufQueue&, std::string> ServicePipeline; typedef Pipeline<IOBufQueue&, std::string> ServicePipeline;
class SimpleDecode : public ByteToMessageCodec {
public:
virtual std::unique_ptr<IOBuf> decode(
Context* ctx, IOBufQueue& buf, size_t&) {
return buf.move();
}
};
class EchoService : public Service<std::string, std::string> { class EchoService : public Service<std::string, std::string> {
public: public:
virtual Future<std::string> operator()(std::string req) override { virtual Future<std::string> operator()(std::string req) override {
...@@ -45,10 +54,12 @@ class ServerPipelineFactory ...@@ -45,10 +54,12 @@ class ServerPipelineFactory
: public PipelineFactory<ServicePipeline> { : public PipelineFactory<ServicePipeline> {
public: public:
ServicePipeline* newPipeline( std::unique_ptr<ServicePipeline, folly::DelayedDestruction::Destructor>
std::shared_ptr<AsyncSocket> socket) override { newPipeline(std::shared_ptr<AsyncSocket> socket) override {
auto pipeline = new ServicePipeline(); std::unique_ptr<ServicePipeline, folly::DelayedDestruction::Destructor> pipeline(
new ServicePipeline());
pipeline->addBack(AsyncSocketHandler(socket)); pipeline->addBack(AsyncSocketHandler(socket));
pipeline->addBack(SimpleDecode());
pipeline->addBack(StringCodec()); pipeline->addBack(StringCodec());
pipeline->addBack(SerialServerDispatcher<Req, Resp>(&service_)); pipeline->addBack(SerialServerDispatcher<Req, Resp>(&service_));
pipeline->finalize(); pipeline->finalize();
...@@ -63,11 +74,14 @@ template <typename Req, typename Resp> ...@@ -63,11 +74,14 @@ template <typename Req, typename Resp>
class ClientPipelineFactory : public PipelineFactory<ServicePipeline> { class ClientPipelineFactory : public PipelineFactory<ServicePipeline> {
public: public:
ServicePipeline* newPipeline( std::unique_ptr<ServicePipeline, folly::DelayedDestruction::Destructor>
std::shared_ptr<AsyncSocket> socket) override { newPipeline(std::shared_ptr<AsyncSocket> socket) override {
auto pipeline = new ServicePipeline(); std::unique_ptr<ServicePipeline, folly::DelayedDestruction::Destructor> pipeline(
new ServicePipeline());
pipeline->addBack(AsyncSocketHandler(socket)); pipeline->addBack(AsyncSocketHandler(socket));
pipeline->addBack(SimpleDecode());
pipeline->addBack(StringCodec()); pipeline->addBack(StringCodec());
pipeline->finalize();
return pipeline; return pipeline;
} }
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment