• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "Utils.h"
18 
19 #include <webrtc/AdbWebSocketHandler.h>
20 #include <webrtc/DTLS.h>
21 #include <webrtc/MyWebSocketHandler.h>
22 #include <webrtc/RTPSocketHandler.h>
23 #include <webrtc/ServerState.h>
24 #include <webrtc/STUNClient.h>
25 #include <webrtc/STUNMessage.h>
26 
27 #include <https/HTTPServer.h>
28 #include <https/PlainSocket.h>
29 #include <https/RunLoop.h>
30 #include <https/SafeCallbackable.h>
31 #include <https/SSLSocket.h>
32 #include <https/Support.h>
33 
34 #include <iostream>
35 #include <unordered_map>
36 
37 #include <netdb.h>
38 
39 #include <gflags/gflags.h>
40 
41 DEFINE_int32(http_server_port, 8443, "The port for the http server.");
42 DEFINE_bool(use_secure_http, true, "Whether to use HTTPS or HTTP.");
43 DEFINE_string(
44         public_ip,
45         "0.0.0.0",
46         "Public IPv4 address of your server, a.b.c.d format");
47 DEFINE_string(
48         assets_dir,
49         "webrtc",
50         "Directory with location of webpage assets.");
51 DEFINE_string(
52         certs_dir,
53         "webrtc/certs",
54         "Directory to certificates.");
55 
56 DEFINE_int32(touch_fd, -1, "An fd to listen on for touch connections.");
57 DEFINE_int32(keyboard_fd, -1, "An fd to listen on for keyboard connections.");
58 DEFINE_int32(frame_server_fd, -1, "An fd to listen on for frame updates");
59 DEFINE_bool(write_virtio_input, false, "Whether to send input events in virtio format.");
60 
61 DEFINE_string(adb, "", "Interface:port of local adb service.");
62 
63 DEFINE_string(
64         stun_server,
65         "stun.l.google.com:19302",
66         "host:port of STUN server to use for public address resolution");
67 
main(int argc,char ** argv)68 int main(int argc, char **argv) {
69     ::gflags::ParseCommandLineFlags(&argc, &argv, true);
70 
71     SSLSocket::Init();
72     DTLS::Init();
73 
74     if (FLAGS_public_ip.empty() || FLAGS_public_ip == "0.0.0.0") {
75         // NOTE: We only contact the external STUN server once upon startup
76         // to determine our own public IP.
77         // This only works if NAT does not remap ports, i.e. a local port 15550
78         // is visible to the outside world on port 15550 as well.
79         // If this condition is not met, this code will have to be modified
80         // and a STUN request made for each locally bound socket before
81         // fulfilling a "MyWebSocketHandler::getCandidate" ICE request.
82 
83         const addrinfo kHints = {
84             AI_ADDRCONFIG,
85             PF_INET,
86             SOCK_DGRAM,
87             IPPROTO_UDP,
88             0,  // ai_addrlen
89             nullptr,  // ai_addr
90             nullptr,  // ai_canonname
91             nullptr  // ai_next
92         };
93 
94         auto pieces = SplitString(FLAGS_stun_server, ':');
95         CHECK_EQ(pieces.size(), 2u);
96 
97         addrinfo *infos;
98         CHECK(!getaddrinfo(pieces[0].c_str(), pieces[1].c_str(), &kHints, &infos));
99 
100         sockaddr_storage stunAddr;
101         memcpy(&stunAddr, infos->ai_addr, infos->ai_addrlen);
102 
103         freeaddrinfo(infos);
104         infos = nullptr;
105 
106         CHECK_EQ(stunAddr.ss_family, AF_INET);
107 
108         std::mutex lock;
109         std::condition_variable cond;
110         bool done = false;
111 
112         auto runLoop = std::make_shared<RunLoop>("STUN");
113 
114         auto stunClient = std::make_shared<STUNClient>(
115                 runLoop,
116                 reinterpret_cast<const sockaddr_in &>(stunAddr),
117                 [&lock, &cond, &done](int result, const std::string &myPublicIp) {
118                     CHECK(!result);
119                     LOG(INFO)
120                         << "STUN-discovered public IP: " << myPublicIp;
121 
122                     FLAGS_public_ip = myPublicIp;
123 
124                     std::lock_guard autoLock(lock);
125                     done = true;
126                     cond.notify_all();
127                 });
128 
129         stunClient->run();
130 
131         std::unique_lock autoLock(lock);
132         while (!done) {
133             cond.wait(autoLock);
134         }
135     }
136 
137     auto runLoop = RunLoop::main();
138 
139     auto state = std::make_shared<ServerState>(
140             runLoop, ServerState::VideoFormat::VP8);
141 
142     auto port = FLAGS_http_server_port;
143 
144     auto httpd = std::make_shared<HTTPServer>(
145             runLoop,
146             "0.0.0.0",
147             port,
148             FLAGS_use_secure_http
149                 ? ServerSocket::TransportType::TLS
150                 : ServerSocket::TransportType::TCP,
151             FLAGS_certs_dir + "/server.crt",
152             FLAGS_certs_dir + "/server.key");
153 
154     const std::string index_html = FLAGS_assets_dir + "/index.html";
155     const std::string logcat_js = FLAGS_assets_dir + "/js/logcat.js";
156     const std::string receive_js = FLAGS_assets_dir + "/js/receive.js";
157     const std::string viewpane_js = FLAGS_assets_dir + "/js/viewpane.js";
158     const std::string style_css = FLAGS_assets_dir + "/style.css";
159 
160     httpd->addStaticFile("/index.html", index_html.c_str());
161     httpd->addStaticFile("/js/logcat.js", logcat_js.c_str());
162     httpd->addStaticFile("/js/receive.js", receive_js.c_str());
163     httpd->addStaticFile("/js/viewpane.js", viewpane_js.c_str());
164     httpd->addStaticFile("/style.css", style_css.c_str());
165 
166     httpd->addWebSocketHandlerFactory(
167             "/control",
168             [runLoop, state]{
169                 auto id = state->acquireHandlerId();
170 
171                 auto handler =
172                     std::make_shared<MyWebSocketHandler>(runLoop, state, id);
173 
174                 return std::make_pair(0 /* OK */, handler);
175             });
176 
177     if (!FLAGS_adb.empty()) {
178         httpd->addWebSocketHandlerFactory(
179                 "/control_adb",
180                 [runLoop]{
181                     auto handler = std::make_shared<AdbWebSocketHandler>(
182                             runLoop, FLAGS_adb);
183 
184                     handler->run();
185 
186                     return std::make_pair(0 /* OK */, handler);
187                 });
188     }
189 
190     httpd->run();
191     runLoop->run();
192 
193     return 0;
194 }
195