• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,
38             "Missing port number\nusage: streaming_playback_controller "
39             "<server-port>\n");
40     return 1;
41   }
42   int port = atoi(argv[1]);
43   if (port <= 0 || port > UINT16_MAX) {
44     dprintf(STDERR_FILENO, "Invalid port number: %d\n", port);
45     return 1;
46   }
47 
48   int fd = socket(AF_INET, SOCK_DGRAM, 0);
49   if (fd == -1) {
50     perror("socket()");
51     return 1;
52   }
53   // On non-Linux, the SOCK_NONBLOCK option is not available, so use the
54   // more-portable method of calling fcntl() to set this behavior.
55   if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) == -1) {
56     perror("fcntl(F_SETFL, +O_NONBLOCK)");
57     return 1;
58   }
59 
60   struct sockaddr_in address = {};
61   address.sin_family = AF_INET;
62   address.sin_port = 0;
63   address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
64   int reuse = 1;
65   int result = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
66   if (result == -1) {
67     perror("setsockopt()");
68     return 1;
69   }
70   result = bind(fd, (struct sockaddr*)(&address), sizeof(address));
71   if (result == -1) {
72     perror("bind()");
73     return 1;
74   }
75 
76   struct sockaddr_in server_address;
77   server_address.sin_family = AF_INET;
78   server_address.sin_port = htons(static_cast<uint16_t>(port));
79   server_address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
80 
81   UdpTransport transport(fd, server_address);
82   auto* clock = quic::QuicChromiumClock::GetInstance();
83   std::vector<FakeTask> tasks;
84   scoped_refptr<FakeTaskRunner> task_runner =
85       base::MakeRefCounted<FakeTaskRunner>(&tasks);
86   auto alarm_factory =
87       std::make_unique<net::QuicChromiumAlarmFactory>(task_runner.get(), clock);
88   quic::QuartcFactoryConfig factory_config;
89   factory_config.alarm_factory = alarm_factory.get();
90   factory_config.clock = clock;
91   quic::QuartcFactory factory(factory_config);
92 
93   quic::QuartcSessionConfig session_config;
94   session_config.perspective = quic::Perspective::IS_CLIENT;
95   session_config.unique_remote_server_id = "asdf";
96   session_config.packet_transport = &transport;
97   // rest are defaults
98 
99   auto session = factory.CreateQuartcSession(session_config);
100   SessionDelegate session_delegate;
101   session->SetDelegate(&session_delegate);
102 
103   StreamDelegate outgoing_delegate;
104 
105   session->OnTransportCanWrite();
106   session->StartCryptoHandshake();
107   auto last = clock->WallNow();
108   bool once = false;
109   while (true) {
110     auto now = clock->WallNow();
111     for (auto it = tasks.begin(); it != tasks.end();) {
112       auto& next_task = *it;
113       next_task.delay -= base::TimeDelta::FromMicroseconds(
114           now.ToUNIXMicroseconds() - last.ToUNIXMicroseconds());
115       if (next_task.delay.InMicroseconds() < 0) {
116         printf("task: %s\n", next_task.whence.ToString().c_str());
117         std::move(next_task.task).Run();
118         it = tasks.erase(it);
119       } else {
120         ++it;
121       }
122     }
123     last = now;
124     // NOTE: The stream will not close immediately on send, because it waits for
125     // ACKs, including for the fin bit.  Calling CloseConnection, however,
126     // immediately closes the connection so it's safe to exit immediately here.
127     if (outgoing_delegate.closed()) {
128       session->CloseConnection("all your base");
129       break;
130     }
131     struct sockaddr_in peer_address;
132     socklen_t addrlen = sizeof(peer_address);
133     char buffer[quic::kMaxPacketSize] = {};
134     int buffer_length = sizeof(buffer);
135     result = recvfrom(fd, buffer, buffer_length, 0,
136                       (struct sockaddr*)(&peer_address), &addrlen);
137     if ((result == -1 && errno != EWOULDBLOCK && errno != EAGAIN) ||
138         addrlen != sizeof(peer_address)) {
139       perror("recvfrom()");
140       return 1;
141     } else if (result > 0) {
142       printf("recvfrom()\n");
143       session->OnTransportReceived(buffer, result);
144       if (session->IsCryptoHandshakeConfirmed() &&
145           session->IsEncryptionEstablished() && !once) {
146         auto* stream = session->CreateOutgoingDynamicStream();
147         stream->SetDelegate(&outgoing_delegate);
148 
149         // TODO(btolsch): This seems odd.  Can we do better when reimplementing
150         // platform/impl?
151         // TODO(btolsch): Specify the number of copies/refcounts per write.
152         char data[] = "turtle";
153         auto buffer = base::MakeRefCounted<net::IOBuffer>(sizeof(data) - 1);
154         int length = sizeof(data) - 1;
155         memcpy(buffer->data(), data, sizeof(data) - 1);
156         stream->WriteMemSlices(
157             quic::QuicMemSliceSpan(
158                 quic::QuicMemSliceSpanImpl(&buffer, &length, 1)),
159             true);
160         once = true;
161       }
162     }
163   }
164 
165   return 0;
166 }
167