1// Copyright 2019 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "dap/network.h"
16
17#include "socket.h"
18
19#include <atomic>
20#include <mutex>
21#include <string>
22#include <thread>
23
24namespace {
25
26class Impl : public dap::net::Server {
27 public:
28 Impl() : stopped{true} {}
29
30 ~Impl() { stop(); }
31
32 bool start(int port,
33 const OnConnect& onConnect,
34 const OnError& onError) override {
35 std::unique_lock<std::mutex> lock(mutex);
36 stopWithLock();
37 socket = std::unique_ptr<dap::Socket>(
38 new dap::Socket("localhost", std::to_string(port).c_str()));
39
40 if (!socket->isOpen()) {
41 onError("Failed to open socket");
42 return false;
43 }
44
45 stopped = false;
46 thread = std::thread([=] {
47 while (true) {
48 if (auto rw = socket->accept()) {
49 onConnect(rw);
50 continue;
51 }
52 if (!stopped) {
53 onError("Failed to accept connection");
54 }
55 break;
56 };
57 });
58
59 return true;
60 }
61
62 void stop() override {
63 std::unique_lock<std::mutex> lock(mutex);
64 stopWithLock();
65 }
66
67 private:
68 bool isRunning() { return !stopped; }
69
70 void stopWithLock() {
71 if (!stopped.exchange(true)) {
72 socket->close();
73 thread.join();
74 }
75 }
76
77 std::mutex mutex;
78 std::thread thread;
79 std::unique_ptr<dap::Socket> socket;
80 std::atomic<bool> stopped;
81 OnError errorHandler;
82};
83
84} // anonymous namespace
85
86namespace dap {
87namespace net {
88
89std::unique_ptr<Server> Server::create() {
90 return std::unique_ptr<Server>(new Impl());
91}
92
93std::shared_ptr<ReaderWriter> connect(const char* addr,
94 int port,
95 uint32_t timeoutMillis) {
96 return Socket::connect(addr, std::to_string(port).c_str(), timeoutMillis);
97}
98
99} // namespace net
100} // namespace dap
101