blob: eea28c0c1e335ca8a0f3b2dfa8170c79a04b6fe2 [file] [log] [blame]
Vitaly Buka4615e0d2015-10-14 15:35:12 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Vitaly Bukacd850602015-09-21 17:23:57 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Johan Euphrosine3523fdd2015-10-14 20:46:05 -07005#include "examples/provider/ssl_stream.h"
Vitaly Bukacd850602015-09-21 17:23:57 -07006
Vitaly Buka10e69bc2015-10-16 01:21:07 -07007#include <openssl/err.h>
8
Vitaly Bukacd850602015-09-21 17:23:57 -07009#include <base/bind.h>
Vitaly Buka10e69bc2015-10-16 01:21:07 -070010#include <base/bind_helpers.h>
Vitaly Buka1e363672015-09-25 14:01:16 -070011#include <weave/provider/task_runner.h>
Vitaly Bukacd850602015-09-21 17:23:57 -070012
13namespace weave {
14namespace examples {
15
Johan Euphrosine2121c192015-10-15 14:11:55 -070016namespace {
Vitaly Buka10e69bc2015-10-16 01:21:07 -070017
18void AddSslError(ErrorPtr* error,
19 const tracked_objects::Location& location,
20 const std::string& error_code,
21 unsigned long ssl_error_code) {
22 ERR_load_BIO_strings();
Johan Euphrosine2121c192015-10-15 14:11:55 -070023 SSL_load_error_strings();
Vitaly Buka10e69bc2015-10-16 01:21:07 -070024 Error::AddToPrintf(error, location, "ssl_stream", error_code, "%s: %s",
25 ERR_lib_error_string(ssl_error_code),
26 ERR_reason_error_string(ssl_error_code));
Johan Euphrosine2121c192015-10-15 14:11:55 -070027}
Vitaly Buka10e69bc2015-10-16 01:21:07 -070028
29void RetryAsyncTask(provider::TaskRunner* task_runner,
30 const tracked_objects::Location& location,
31 const base::Closure& task) {
32 task_runner->PostDelayedTask(FROM_HERE, task,
33 base::TimeDelta::FromMilliseconds(100));
34}
35
Johan Euphrosine2121c192015-10-15 14:11:55 -070036} // namespace
37
Vitaly Buka10e69bc2015-10-16 01:21:07 -070038void SSLStream::SslDeleter::operator()(BIO* bio) const {
39 BIO_free(bio);
40}
41
42void SSLStream::SslDeleter::operator()(SSL* ssl) const {
43 SSL_free(ssl);
44}
45
46void SSLStream::SslDeleter::operator()(SSL_CTX* ctx) const {
47 SSL_CTX_free(ctx);
48}
49
50SSLStream::SSLStream(provider::TaskRunner* task_runner,
51 std::unique_ptr<BIO, SslDeleter> stream_bio)
Johan Euphrosine2121c192015-10-15 14:11:55 -070052 : task_runner_{task_runner} {
Vitaly Buka10e69bc2015-10-16 01:21:07 -070053 ctx_.reset(SSL_CTX_new(TLSv1_2_client_method()));
54 CHECK(ctx_);
55 ssl_.reset(SSL_new(ctx_.get()));
56
57 SSL_set_bio(ssl_.get(), stream_bio.get(), stream_bio.get());
58 stream_bio.release(); // Owned by ssl now.
59 SSL_set_connect_state(ssl_.get());
Johan Euphrosine2121c192015-10-15 14:11:55 -070060}
Vitaly Bukacd850602015-09-21 17:23:57 -070061
62SSLStream::~SSLStream() {
Vitaly Bukada987282015-09-23 16:50:40 -070063 CancelPendingOperations();
Vitaly Bukacd850602015-09-21 17:23:57 -070064}
65
Vitaly Buka10e69bc2015-10-16 01:21:07 -070066void SSLStream::RunTask(const base::Closure& task) {
Vitaly Buka6c5c99d2015-09-24 17:00:18 -070067 task.Run();
Vitaly Bukacd850602015-09-21 17:23:57 -070068}
69
Vitaly Buka4ebd3292015-09-23 18:04:17 -070070void SSLStream::Read(void* buffer,
71 size_t size_to_read,
Vitaly Buka74763422015-10-11 00:39:52 -070072 const ReadCallback& callback) {
Vitaly Bukacd850602015-09-21 17:23:57 -070073 int res = SSL_read(ssl_.get(), buffer, size_to_read);
74 if (res > 0) {
75 task_runner_->PostDelayedTask(
76 FROM_HERE,
Vitaly Buka10e69bc2015-10-16 01:21:07 -070077 base::Bind(&SSLStream::RunTask, weak_ptr_factory_.GetWeakPtr(),
Vitaly Buka74763422015-10-11 00:39:52 -070078 base::Bind(callback, res, nullptr)),
Vitaly Bukacd850602015-09-21 17:23:57 -070079 {});
80 return;
81 }
82
Vitaly Buka10e69bc2015-10-16 01:21:07 -070083 int err = SSL_get_error(ssl_.get(), res);
Vitaly Bukacd850602015-09-21 17:23:57 -070084
85 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
Vitaly Buka10e69bc2015-10-16 01:21:07 -070086 return RetryAsyncTask(
87 task_runner_, FROM_HERE,
88 base::Bind(&SSLStream::Read, weak_ptr_factory_.GetWeakPtr(), buffer,
89 size_to_read, callback));
Vitaly Bukacd850602015-09-21 17:23:57 -070090 }
91
92 ErrorPtr weave_error;
Vitaly Buka10e69bc2015-10-16 01:21:07 -070093 AddSslError(&weave_error, FROM_HERE, "read_failed", err);
94 return task_runner_->PostDelayedTask(
Vitaly Bukacd850602015-09-21 17:23:57 -070095 FROM_HERE,
Vitaly Buka10e69bc2015-10-16 01:21:07 -070096 base::Bind(&SSLStream::RunTask, weak_ptr_factory_.GetWeakPtr(),
Vitaly Buka74763422015-10-11 00:39:52 -070097 base::Bind(callback, 0, base::Passed(&weave_error))),
Vitaly Bukacd850602015-09-21 17:23:57 -070098 {});
Vitaly Bukacd850602015-09-21 17:23:57 -070099}
100
Vitaly Buka1fd619a2015-09-24 11:46:05 -0700101void SSLStream::Write(const void* buffer,
102 size_t size_to_write,
Vitaly Buka74763422015-10-11 00:39:52 -0700103 const WriteCallback& callback) {
Vitaly Bukacd850602015-09-21 17:23:57 -0700104 int res = SSL_write(ssl_.get(), buffer, size_to_write);
105 if (res > 0) {
106 buffer = static_cast<const char*>(buffer) + res;
107 size_to_write -= res;
108 if (size_to_write == 0) {
Vitaly Buka10e69bc2015-10-16 01:21:07 -0700109 return task_runner_->PostDelayedTask(
Vitaly Bukacd850602015-09-21 17:23:57 -0700110 FROM_HERE,
Vitaly Buka10e69bc2015-10-16 01:21:07 -0700111 base::Bind(&SSLStream::RunTask, weak_ptr_factory_.GetWeakPtr(),
Vitaly Buka74763422015-10-11 00:39:52 -0700112 base::Bind(callback, nullptr)),
Vitaly Bukacd850602015-09-21 17:23:57 -0700113 {});
Vitaly Bukacd850602015-09-21 17:23:57 -0700114 }
115
Vitaly Buka10e69bc2015-10-16 01:21:07 -0700116 return RetryAsyncTask(
117 task_runner_, FROM_HERE,
118 base::Bind(&SSLStream::Write, weak_ptr_factory_.GetWeakPtr(), buffer,
119 size_to_write, callback));
Vitaly Bukacd850602015-09-21 17:23:57 -0700120 }
121
Vitaly Buka10e69bc2015-10-16 01:21:07 -0700122 int err = SSL_get_error(ssl_.get(), res);
Vitaly Bukacd850602015-09-21 17:23:57 -0700123
124 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
Vitaly Buka10e69bc2015-10-16 01:21:07 -0700125 return RetryAsyncTask(
126 task_runner_, FROM_HERE,
127 base::Bind(&SSLStream::Write, weak_ptr_factory_.GetWeakPtr(), buffer,
128 size_to_write, callback));
Vitaly Bukacd850602015-09-21 17:23:57 -0700129 }
130
131 ErrorPtr weave_error;
Vitaly Buka10e69bc2015-10-16 01:21:07 -0700132 AddSslError(&weave_error, FROM_HERE, "write_failed", err);
Vitaly Bukacd850602015-09-21 17:23:57 -0700133 task_runner_->PostDelayedTask(
Vitaly Buka10e69bc2015-10-16 01:21:07 -0700134 FROM_HERE, base::Bind(&SSLStream::RunTask, weak_ptr_factory_.GetWeakPtr(),
135 base::Bind(callback, base::Passed(&weave_error))),
Vitaly Bukacd850602015-09-21 17:23:57 -0700136 {});
Vitaly Bukacd850602015-09-21 17:23:57 -0700137}
138
Vitaly Bukada987282015-09-23 16:50:40 -0700139void SSLStream::CancelPendingOperations() {
Vitaly Bukacd850602015-09-21 17:23:57 -0700140 weak_ptr_factory_.InvalidateWeakPtrs();
141}
142
Vitaly Buka10e69bc2015-10-16 01:21:07 -0700143void SSLStream::Connect(
144 provider::TaskRunner* task_runner,
145 const std::string& host,
146 uint16_t port,
147 const provider::Network::OpenSslSocketCallback& callback) {
148 SSL_library_init();
Vitaly Bukacd850602015-09-21 17:23:57 -0700149
150 char end_point[255];
151 snprintf(end_point, sizeof(end_point), "%s:%u", host.c_str(), port);
Vitaly Buka10e69bc2015-10-16 01:21:07 -0700152
153 std::unique_ptr<BIO, SslDeleter> stream_bio(BIO_new_connect(end_point));
Vitaly Bukacd850602015-09-21 17:23:57 -0700154 CHECK(stream_bio);
Vitaly Buka10e69bc2015-10-16 01:21:07 -0700155 BIO_set_nbio(stream_bio.get(), 1);
Vitaly Bukacd850602015-09-21 17:23:57 -0700156
Vitaly Buka10e69bc2015-10-16 01:21:07 -0700157 std::unique_ptr<SSLStream> stream{
158 new SSLStream{task_runner, std::move(stream_bio)}};
159 ConnectBio(std::move(stream), callback);
160}
161
162void SSLStream::ConnectBio(
163 std::unique_ptr<SSLStream> stream,
164 const provider::Network::OpenSslSocketCallback& callback) {
165 BIO* bio = SSL_get_rbio(stream->ssl_.get());
166 if (BIO_do_connect(bio) == 1)
167 return DoHandshake(std::move(stream), callback);
168
169 auto task_runner = stream->task_runner_;
170 if (BIO_should_retry(bio)) {
171 return RetryAsyncTask(
172 task_runner, FROM_HERE,
173 base::Bind(&SSLStream::ConnectBio, base::Passed(&stream), callback));
Vitaly Bukacd850602015-09-21 17:23:57 -0700174 }
175
Vitaly Buka10e69bc2015-10-16 01:21:07 -0700176 ErrorPtr error;
177 AddSslError(&error, FROM_HERE, "connect_failed", ERR_get_error());
178 task_runner->PostDelayedTask(
179 FROM_HERE, base::Bind(callback, nullptr, base::Passed(&error)), {});
180}
Vitaly Bukacd850602015-09-21 17:23:57 -0700181
Vitaly Buka10e69bc2015-10-16 01:21:07 -0700182void SSLStream::DoHandshake(
183 std::unique_ptr<SSLStream> stream,
184 const provider::Network::OpenSslSocketCallback& callback) {
185 int res = SSL_do_handshake(stream->ssl_.get());
186 auto task_runner = stream->task_runner_;
187 if (res == 1) {
188 return task_runner->PostDelayedTask(
189 FROM_HERE, base::Bind(callback, base::Passed(&stream), nullptr), {});
Vitaly Bukacd850602015-09-21 17:23:57 -0700190 }
Vitaly Buka10e69bc2015-10-16 01:21:07 -0700191
192 res = SSL_get_error(stream->ssl_.get(), res);
193
194 if (res == SSL_ERROR_WANT_READ || res == SSL_ERROR_WANT_WRITE) {
195 return RetryAsyncTask(
196 task_runner, FROM_HERE,
197 base::Bind(&SSLStream::DoHandshake, base::Passed(&stream), callback));
198 }
199
200 ErrorPtr error;
201 AddSslError(&error, FROM_HERE, "handshake_failed", res);
202 task_runner->PostDelayedTask(
203 FROM_HERE, base::Bind(callback, nullptr, base::Passed(&error)), {});
Vitaly Bukacd850602015-09-21 17:23:57 -0700204}
205
206} // namespace examples
207} // namespace weave