Loading...
Searching...
No Matches
async_acceptor.cpp
Go to the documentation of this file.
1/*
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 */
19
21
22#include <glog/logging.h>
23#include <signal.h>
24
25#include <thread>
26
27namespace resdb {
28
29AsyncAcceptor::Session::Session(boost::asio::io_service* io_service,
30 CallBack call_back_func)
31 : io_service_(io_service),
32 client_socket_(*io_service_),
33 recv_buffer_(nullptr),
34 status_(0),
35 call_back_func_(call_back_func) {}
36
37AsyncAcceptor::Session::~Session() { Close(); }
38
39boost::asio::ip::tcp::socket* AsyncAcceptor::Session::GetSocket() {
40 return &client_socket_;
41}
42
43void AsyncAcceptor::Session::Close() {
44 if (client_socket_.is_open()) {
45 client_socket_.cancel();
46 }
47 if (recv_buffer_ && status_ != 0) {
48 delete recv_buffer_;
49 recv_buffer_ = nullptr;
50 }
51}
52
53void AsyncAcceptor::Session::StartRead() {
54 if (status_ == 0) {
55 // read len
56 recv_buffer_ = reinterpret_cast<char*>(&data_size_);
57 data_size_ = 0;
58 need_size_ = sizeof(data_size_);
59 current_idx_ = 0;
60 memset(recv_buffer_, 0, need_size_);
61 OnRead();
62 } else {
63 need_size_ = data_size_;
64 current_idx_ = 0;
65 if (recv_buffer_) {
66 delete recv_buffer_;
67 }
68 recv_buffer_ = new char[need_size_];
69 memset(recv_buffer_, 0, need_size_);
70 OnRead();
71 }
72}
73
74void AsyncAcceptor::Session::ReadDone() {
75 if (status_ == 1) {
76 call_back_func_(recv_buffer_, data_size_);
77 delete recv_buffer_;
78 } else {
79 data_size_ = *reinterpret_cast<size_t*>(recv_buffer_);
80 if (data_size_ > 1e6) {
81 LOG(ERROR) << "read data size:" << data_size_
82 << " data size:" << sizeof(data_size_) << " close socket";
83 Close();
84 return;
85 }
86 }
87 status_ ^= 1;
88 recv_buffer_ = nullptr;
89 // continue to read next msg.
90 StartRead();
91}
92
93void AsyncAcceptor::Session::OnRead() {
94 client_socket_.async_read_some(
95 boost::asio::buffer(recv_buffer_ + current_idx_,
96 need_size_ - current_idx_),
97 [&](const boost::system::error_code& error, // Result of operation.
98 std::size_t bytes_transferred) {
99 if (error || bytes_transferred == 0) {
100 Close();
101 } else {
102 current_idx_ += bytes_transferred;
103 if (current_idx_ >= need_size_) {
104 ReadDone();
105 } else {
106 OnRead();
107 }
108 }
109 });
110}
111
112AsyncAcceptor::AsyncAcceptor(const std::string& ip, int port, int thread_num,
113 CallBack call_back_func)
114 : endpoint_(boost::asio::ip::address::from_string(ip), port),
115 acceptor_(io_service_, endpoint_),
116 call_back_func_(call_back_func) {
117 worker_ = std::make_unique<boost::asio::io_service::work>(io_service_);
118 for (int i = 0; i < thread_num; ++i) {
119 worker_thread_.push_back(std::thread([&]() { io_service_.run(); }));
120 }
121}
122
124 worker_.reset();
125 worker_ = nullptr;
126 io_service_.stop();
127
128 for (auto& sess : sessions_) {
129 if (sess) {
130 sess->Close();
131 }
132 }
133
134 for (auto& worker : worker_thread_) {
135 if (worker.joinable()) {
136 worker.join();
137 }
138 }
139}
140
142 boost::shared_ptr<Session> client_session(
143 new Session(&io_service_, call_back_func_));
144 acceptor_.async_accept(*client_session->GetSocket(),
145 std::bind(&AsyncAcceptor::OnAccept, this,
146 client_session, std::placeholders::_1));
147}
148
149void AsyncAcceptor::OnAccept(boost::shared_ptr<Session> client_session,
150 const boost::system::error_code ec) {
151 if (ec) {
152 LOG(ERROR) << " accept fail";
153 return;
154 }
155
156 StartAccept(); // Add the next accept event.
157
158 sessions_.push_back(client_session);
159 client_session->StartRead();
160}
161
162} // namespace resdb
std::function< void(const char *buffer, size_t len)> CallBack