From: James Sedgwick Date: Mon, 4 May 2015 19:15:16 +0000 (-0700) Subject: Telnet client X-Git-Tag: v0.38.0~13 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=589052a636a717bbf89dfc5c25588cbdaac080a8;p=folly.git Telnet client Summary: A client example to match telnet server. Required a couple additions: * future result when socket actually connects, similar to netty * clients support IOThreadPoolExecutor groups * a pipeline stage to make sure everything runs in the right eventbase thread. Test Plan: fbconfig follg/wangle/example/telnet && fbmake dbg telnet_server telnet_client Reviewed By: hans@fb.com Subscribers: doug, fugalh, folly-diffs@, jsedgwick, yfeldblum, chalfant FB internal diff: D2010289 Signature: t1:2010289:1430766232:65c6f946e454000f6ea9f41b49197ddbeea5ba3f --- diff --git a/folly/Makefile.am b/folly/Makefile.am index b11be450..ad215492 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -276,6 +276,7 @@ nobase_follyinclude_HEADERS = \ wangle/bootstrap/ServerSocketFactory.h \ wangle/bootstrap/ClientBootstrap.h \ wangle/channel/AsyncSocketHandler.h \ + wangle/channel/EventBaseHandler.h \ wangle/channel/Handler.h \ wangle/channel/HandlerContext.h \ wangle/channel/HandlerContext-inl.h \ diff --git a/folly/wangle/bootstrap/BootstrapTest.cpp b/folly/wangle/bootstrap/BootstrapTest.cpp index 0696f71f..724afec9 100644 --- a/folly/wangle/bootstrap/BootstrapTest.cpp +++ b/folly/wangle/bootstrap/BootstrapTest.cpp @@ -34,10 +34,9 @@ class TestClientPipelineFactory : public PipelineFactory { public: std::unique_ptr newPipeline(std::shared_ptr sock) { - CHECK(sock->good()); - // We probably aren't connected immedately, check after a small delay EventBaseManager::get()->getEventBase()->tryRunAfterDelay([sock](){ + CHECK(sock->good()); CHECK(sock->readable()); }, 100); return nullptr; diff --git a/folly/wangle/bootstrap/ClientBootstrap.h b/folly/wangle/bootstrap/ClientBootstrap.h index 94e6789f..3ae2ce4f 100644 --- a/folly/wangle/bootstrap/ClientBootstrap.h +++ b/folly/wangle/bootstrap/ClientBootstrap.h @@ -16,6 +16,9 @@ #pragma once #include +#include +#include +#include namespace folly { @@ -25,20 +28,60 @@ namespace folly { */ template class ClientBootstrap { + + class ConnectCallback : public AsyncSocket::ConnectCallback { + public: + ConnectCallback(Promise promise, ClientBootstrap* bootstrap) + : promise_(std::move(promise)) + , bootstrap_(bootstrap) {} + + void connectSuccess() noexcept override { + promise_.setValue(bootstrap_->getPipeline()); + delete this; + } + + void connectErr(const AsyncSocketException& ex) noexcept override { + promise_.setException( + folly::make_exception_wrapper(ex)); + delete this; + } + private: + Promise promise_; + ClientBootstrap* bootstrap_; + }; + public: ClientBootstrap() { } + + ClientBootstrap* group( + std::shared_ptr group) { + group_ = group; + return this; + } ClientBootstrap* bind(int port) { port_ = port; return this; } - ClientBootstrap* connect(SocketAddress address) { + Future connect(SocketAddress address) { DCHECK(pipelineFactory_); - pipeline_= - pipelineFactory_->newPipeline( - AsyncSocket::newSocket( - EventBaseManager::get()->getEventBase(), address)); - return this; + auto base = EventBaseManager::get()->getEventBase(); + if (group_) { + base = group_->getEventBase(); + } + Future retval((Pipeline*)nullptr); + base->runImmediatelyOrRunInEventBaseThreadAndWait([&](){ + auto socket = AsyncSocket::newSocket(base); + Promise promise; + retval = promise.getFuture(); + socket->connect( + new ConnectCallback(std::move(promise), this), address); + pipeline_ = pipelineFactory_->newPipeline(socket); + if (pipeline_) { + pipeline_->attachTransport(socket); + } + }); + return retval; } ClientBootstrap* pipelineFactory( @@ -60,6 +103,7 @@ class ClientBootstrap { int port_; std::shared_ptr> pipelineFactory_; + std::shared_ptr group_; }; } // namespace diff --git a/folly/wangle/channel/EventBaseHandler.h b/folly/wangle/channel/EventBaseHandler.h new file mode 100644 index 00000000..55290ded --- /dev/null +++ b/folly/wangle/channel/EventBaseHandler.h @@ -0,0 +1,45 @@ +/* + * Copyright 2015 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +namespace folly { namespace wangle { + +class EventBaseHandler : public OutboundBytesToBytesHandler { + public: + folly::Future write( + Context* ctx, + std::unique_ptr buf) override { + folly::Future retval; + DCHECK(ctx->getTransport()); + DCHECK(ctx->getTransport()->getEventBase()); + ctx->getTransport()->getEventBase()->runImmediatelyOrRunInEventBaseThreadAndWait([&](){ + retval = ctx->fireWrite(std::move(buf)); + }); + return retval; + } + + Future close(Context* ctx) override { + DCHECK(ctx->getTransport()); + DCHECK(ctx->getTransport()->getEventBase()); + Future retval; + ctx->getTransport()->getEventBase()->runImmediatelyOrRunInEventBaseThreadAndWait([&](){ + retval = ctx->fireClose(); + }); + return retval; + } +}; + +}} // namespace