1 // Copyright (c) 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <arpa/inet.h>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <netinet/in.h>
9 #include <netinet/ip.h>
10 #include <stdio.h>
11 #include <sys/socket.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14
15 #include <memory>
16 #include <vector>
17
18 #include "base/at_exit.h"
19 #include "base/command_line.h"
20 #include "base/logging.h"
21 #include "net/quic/quic_chromium_alarm_factory.h"
22 #include "net/third_party/quic/core/quic_constants.h"
23 #include "net/third_party/quic/platform/impl/quic_chromium_clock.h"
24 #include "net/third_party/quic/quartc/quartc_factory.h"
25 #include "third_party/chromium_quic/demo/delegates.h"
26
main(int argc,char ** argv)27 int main(int argc, char** argv) {
28 base::AtExitManager exit_manager;
29 base::CommandLine::Init(argc, argv);
30 logging::LoggingSettings logging_settings;
31 logging_settings.logging_dest = logging::LOG_TO_FILE;
32 logging_settings.log_file = "/dev/stderr";
33 logging_settings.lock_log = logging::DONT_LOCK_LOG_FILE;
34 logging::InitLogging(logging_settings);
35
36 if (argc < 2) {
37 dprintf(STDERR_FILENO, "Missing port number\nusage: demo_server <port>\n");
38 return 1;
39 }
40 int port = atoi(argv[1]);
41 if (port <= 0 || port > UINT16_MAX) {
42 dprintf(STDERR_FILENO, "Invalid port number: %d\n", port);
43 return 1;
44 }
45
46 int fd = socket(AF_INET, SOCK_DGRAM, 0);
47 if (fd == -1) {
48 perror("socket()");
49 return 1;
50 }
51 // On non-Linux, the SOCK_NONBLOCK option is not available, so use the
52 // more-portable method of calling fcntl() to set this behavior.
53 if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) == -1) {
54 perror("fcntl(F_SETFL, +O_NONBLOCK)");
55 return 1;
56 }
57
58 struct sockaddr_in address = {};
59 address.sin_family = AF_INET;
60 address.sin_port = htons(static_cast<uint16_t>(port));
61 address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
62 int reuse = 1;
63 int result = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
64 if (result == -1) {
65 perror("setsockopt()");
66 return 1;
67 }
68 result = bind(fd, (struct sockaddr*)(&address), sizeof(address));
69 if (result == -1) {
70 perror("bind()");
71 return 1;
72 }
73
74 // NOTE: First recvfrom is outside loop so we can initialize the transport
75 // with the client address.
76 struct sockaddr_in client_address;
77 char initial_buffer[quic::kMaxPacketSize] = {};
78 int initial_buffer_length = sizeof(initial_buffer);
79 int read_result = 0;
80 while (true) {
81 socklen_t addrlen = sizeof(client_address);
82 read_result = recvfrom(fd, initial_buffer, initial_buffer_length, 0,
83 (struct sockaddr*)(&client_address), &addrlen);
84 if (read_result > 0) {
85 break;
86 }
87 }
88
89 UdpTransport transport(fd, client_address);
90 auto* clock = quic::QuicChromiumClock::GetInstance();
91 std::vector<FakeTask> tasks;
92 scoped_refptr<FakeTaskRunner> task_runner =
93 base::MakeRefCounted<FakeTaskRunner>(&tasks);
94 auto alarm_factory =
95 std::make_unique<net::QuicChromiumAlarmFactory>(task_runner.get(), clock);
96 quic::QuartcFactoryConfig factory_config;
97 factory_config.alarm_factory = alarm_factory.get();
98 factory_config.clock = clock;
99 quic::QuartcFactory factory(factory_config);
100
101 quic::QuartcSessionConfig session_config;
102 session_config.perspective = quic::Perspective::IS_SERVER;
103 session_config.packet_transport = &transport;
104 // rest are defaults
105
106 auto session = factory.CreateQuartcSession(session_config);
107 SessionDelegate session_delegate;
108 session->SetDelegate(&session_delegate);
109
110 session->OnTransportCanWrite();
111 session->StartCryptoHandshake();
112 session->OnTransportReceived(initial_buffer, read_result);
113 auto last = clock->WallNow();
114 bool once = false;
115 while (true) {
116 auto now = clock->WallNow();
117 for (auto it = tasks.begin(); it != tasks.end();) {
118 auto& next_task = *it;
119 next_task.delay -= base::TimeDelta::FromMicroseconds(
120 now.ToUNIXMicroseconds() - last.ToUNIXMicroseconds());
121 if (next_task.delay.InMicroseconds() < 0) {
122 printf("task: %s\n", next_task.whence.ToString().c_str());
123 std::move(next_task.task).Run();
124 it = tasks.erase(it);
125 } else {
126 ++it;
127 }
128 }
129 last = now;
130 if (session->IsCryptoHandshakeConfirmed() &&
131 session->IsEncryptionEstablished() && !once) {
132 printf("handshake done\n");
133 once = true;
134 }
135 // Client is responsible for closing the connection.
136 if (session_delegate.connection_closed()) {
137 break;
138 }
139 struct sockaddr_in peer_address;
140 socklen_t addrlen = sizeof(peer_address);
141 char buffer[quic::kMaxPacketSize] = {};
142 int buffer_length = sizeof(buffer);
143 result = recvfrom(fd, buffer, buffer_length, 0,
144 (struct sockaddr*)(&peer_address), &addrlen);
145 if ((result == -1 && errno != EWOULDBLOCK && errno != EAGAIN) ||
146 addrlen != sizeof(peer_address)) {
147 perror("recvfrom()");
148 return 1;
149 } else if (result > 0) {
150 printf("recvfrom()\n");
151 session->OnTransportReceived(buffer, result);
152 }
153 }
154
155 return 0;
156 }
157