proxygen
AsyncSSLSocketWriteTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2013-present Facebook, Inc.
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 #include <folly/io/Cursor.h>
22 
23 #include <string>
24 #include <vector>
25 
26 using std::string;
27 using namespace testing;
28 
29 namespace folly {
30 
32  public:
33  static std::shared_ptr<MockAsyncSSLSocket> newSocket(
34  const std::shared_ptr<SSLContext>& ctx,
35  EventBase* evb) {
36  auto sock = std::shared_ptr<MockAsyncSSLSocket>(
37  new MockAsyncSSLSocket(ctx, evb), Destructor());
38  sock->ssl_.reset(SSL_new(ctx->getSSLCtx()));
39  SSL_set_fd(sock->ssl_.get(), -1);
40  return sock;
41  }
42 
43  // Fake constructor sets the state to established without call to connect
44  // or accept
45  MockAsyncSSLSocket(const std::shared_ptr<SSLContext>& ctx, EventBase* evb)
46  : AsyncSocket(evb), AsyncSSLSocket(ctx, evb) {
47  state_ = AsyncSocket::StateEnum::ESTABLISHED;
48  sslState_ = AsyncSSLSocket::SSLStateEnum::STATE_ESTABLISHED;
49  }
50 
51  // mock the calls to SSL_write to see the buffer length and contents
52  MOCK_METHOD3(sslWriteImpl, int(SSL* ssl, const void* buf, int n));
53 
54  // mock the calls to getRawBytesWritten()
55  MOCK_CONST_METHOD0(getRawBytesWritten, size_t());
56 
57  // public wrapper for protected interface
59  const iovec* vec,
62  uint32_t* countWritten,
63  uint32_t* partialWritten) {
64  return performWrite(vec, count, flags, countWritten, partialWritten);
65  }
66 
67  void checkEor(size_t appEor, size_t rawEor) {
68  EXPECT_EQ(appEor, appEorByteNo_);
69  EXPECT_EQ(rawEor, minEorRawByteNo_);
70  }
71 
72  void setAppBytesWritten(size_t n) {
73  appBytesWritten_ = n;
74  }
75 };
76 
78  public:
80  : sslContext_(new SSLContext()),
81  sock_(MockAsyncSSLSocket::newSocket(sslContext_, &eventBase_)) {
82  for (int i = 0; i < 500; i++) {
83  memcpy(source_ + i * 26, "abcdefghijklmnopqrstuvwxyz", 26);
84  }
85  }
86 
87  // Make an iovec containing chunks of the reference text with requested sizes
88  // for each chunk
89  std::unique_ptr<iovec[]> makeVec(std::vector<uint32_t> sizes) {
90  std::unique_ptr<iovec[]> vec(new iovec[sizes.size()]);
91  int i = 0;
92  int pos = 0;
93  for (auto size : sizes) {
94  vec[i].iov_base = (void*)(source_ + pos);
95  vec[i++].iov_len = size;
96  pos += size;
97  }
98  return vec;
99  }
100 
101  // Verify that the given buf/pos matches the reference text
102  void verifyVec(const void* buf, int n, int pos) {
103  ASSERT_EQ(memcmp(source_ + pos, buf, n), 0);
104  }
105 
106  // Update a vec on partial write
107  void consumeVec(iovec* vec, uint32_t countWritten, uint32_t partialWritten) {
108  vec[countWritten].iov_base =
109  ((char*)vec[countWritten].iov_base) + partialWritten;
110  vec[countWritten].iov_len -= partialWritten;
111  }
112 
114  std::shared_ptr<SSLContext> sslContext_;
115  std::shared_ptr<MockAsyncSSLSocket> sock_;
116  char source_[26 * 500];
117 };
118 
119 // The entire vec fits in one packet
120 TEST_F(AsyncSSLSocketWriteTest, write_coalescing1) {
121  int n = 3;
122  auto vec = makeVec({3, 3, 3});
123  EXPECT_CALL(*(sock_.get()), sslWriteImpl(_, _, 9))
124  .WillOnce(Invoke([this](SSL*, const void* buf, int m) {
125  verifyVec(buf, m, 0);
126  return 9;
127  }));
128  uint32_t countWritten = 0;
129  uint32_t partialWritten = 0;
130  sock_->testPerformWrite(
131  vec.get(), n, WriteFlags::NONE, &countWritten, &partialWritten);
132  EXPECT_EQ(countWritten, n);
133  EXPECT_EQ(partialWritten, 0);
134 }
135 
136 // First packet is full, second two go in one packet
137 TEST_F(AsyncSSLSocketWriteTest, write_coalescing2) {
138  int n = 3;
139  auto vec = makeVec({1500, 3, 3});
140  int pos = 0;
141  EXPECT_CALL(*(sock_.get()), sslWriteImpl(_, _, 1500))
142  .WillOnce(Invoke([this, &pos](SSL*, const void* buf, int m) {
143  verifyVec(buf, m, pos);
144  pos += m;
145  return m;
146  }));
147  EXPECT_CALL(*(sock_.get()), sslWriteImpl(_, _, 6))
148  .WillOnce(Invoke([this, &pos](SSL*, const void* buf, int m) {
149  verifyVec(buf, m, pos);
150  pos += m;
151  return m;
152  }));
153  uint32_t countWritten = 0;
154  uint32_t partialWritten = 0;
155  sock_->testPerformWrite(
156  vec.get(), n, WriteFlags::NONE, &countWritten, &partialWritten);
157  EXPECT_EQ(countWritten, n);
158  EXPECT_EQ(partialWritten, 0);
159 }
160 
161 // Two exactly full packets (coalesce ends midway through second chunk)
162 TEST_F(AsyncSSLSocketWriteTest, write_coalescing3) {
163  int n = 3;
164  auto vec = makeVec({1000, 1000, 1000});
165  int pos = 0;
166  EXPECT_CALL(*(sock_.get()), sslWriteImpl(_, _, 1500))
167  .Times(2)
168  .WillRepeatedly(Invoke([this, &pos](SSL*, const void* buf, int m) {
169  verifyVec(buf, m, pos);
170  pos += m;
171  return m;
172  }));
173  uint32_t countWritten = 0;
174  uint32_t partialWritten = 0;
175  sock_->testPerformWrite(
176  vec.get(), n, WriteFlags::NONE, &countWritten, &partialWritten);
177  EXPECT_EQ(countWritten, n);
178  EXPECT_EQ(partialWritten, 0);
179 }
180 
181 // Partial write success midway through a coalesced vec
182 TEST_F(AsyncSSLSocketWriteTest, write_coalescing4) {
183  int n = 5;
184  auto vec = makeVec({300, 300, 300, 300, 300});
185  int pos = 0;
186  EXPECT_CALL(*(sock_.get()), sslWriteImpl(_, _, 1500))
187  .WillOnce(Invoke([this, &pos](SSL*, const void* buf, int m) {
188  verifyVec(buf, m, pos);
189  pos += 1000;
190  return 1000; /* 500 bytes "pending" */
191  }));
192  uint32_t countWritten = 0;
193  uint32_t partialWritten = 0;
194  sock_->testPerformWrite(
195  vec.get(), n, WriteFlags::NONE, &countWritten, &partialWritten);
196  EXPECT_EQ(countWritten, 3);
197  EXPECT_EQ(partialWritten, 100);
198  consumeVec(vec.get(), countWritten, partialWritten);
199  EXPECT_CALL(*(sock_.get()), sslWriteImpl(_, _, 500))
200  .WillOnce(Invoke([this, &pos](SSL*, const void* buf, int m) {
201  verifyVec(buf, m, pos);
202  pos += m;
203  return 500;
204  }));
205  sock_->testPerformWrite(
206  vec.get() + countWritten,
207  n - countWritten,
208  WriteFlags::NONE,
209  &countWritten,
210  &partialWritten);
211  EXPECT_EQ(countWritten, 2);
212  EXPECT_EQ(partialWritten, 0);
213 }
214 
215 // coalesce ends exactly on a buffer boundary
216 TEST_F(AsyncSSLSocketWriteTest, write_coalescing5) {
217  int n = 3;
218  auto vec = makeVec({1000, 500, 500});
219  int pos = 0;
220  EXPECT_CALL(*(sock_.get()), sslWriteImpl(_, _, 1500))
221  .WillOnce(Invoke([this, &pos](SSL*, const void* buf, int m) {
222  verifyVec(buf, m, pos);
223  pos += m;
224  return m;
225  }));
226  EXPECT_CALL(*(sock_.get()), sslWriteImpl(_, _, 500))
227  .WillOnce(Invoke([this, &pos](SSL*, const void* buf, int m) {
228  verifyVec(buf, m, pos);
229  pos += m;
230  return m;
231  }));
232  uint32_t countWritten = 0;
233  uint32_t partialWritten = 0;
234  sock_->testPerformWrite(
235  vec.get(), n, WriteFlags::NONE, &countWritten, &partialWritten);
236  EXPECT_EQ(countWritten, 3);
237  EXPECT_EQ(partialWritten, 0);
238 }
239 
240 // partial write midway through first chunk
241 TEST_F(AsyncSSLSocketWriteTest, write_coalescing6) {
242  int n = 2;
243  auto vec = makeVec({1000, 500});
244  int pos = 0;
245  EXPECT_CALL(*(sock_.get()), sslWriteImpl(_, _, 1500))
246  .WillOnce(Invoke([this, &pos](SSL*, const void* buf, int m) {
247  verifyVec(buf, m, pos);
248  pos += 700;
249  return 700;
250  }));
251  uint32_t countWritten = 0;
252  uint32_t partialWritten = 0;
253  sock_->testPerformWrite(
254  vec.get(), n, WriteFlags::NONE, &countWritten, &partialWritten);
255  EXPECT_EQ(countWritten, 0);
256  EXPECT_EQ(partialWritten, 700);
257  consumeVec(vec.get(), countWritten, partialWritten);
258  EXPECT_CALL(*(sock_.get()), sslWriteImpl(_, _, 800))
259  .WillOnce(Invoke([this, &pos](SSL*, const void* buf, int m) {
260  verifyVec(buf, m, pos);
261  pos += m;
262  return m;
263  }));
264  sock_->testPerformWrite(
265  vec.get() + countWritten,
266  n - countWritten,
267  WriteFlags::NONE,
268  &countWritten,
269  &partialWritten);
270  EXPECT_EQ(countWritten, 2);
271  EXPECT_EQ(partialWritten, 0);
272 }
273 
274 // Repeat coalescing2 with WriteFlags::EOR
275 TEST_F(AsyncSSLSocketWriteTest, write_with_eor1) {
276  int n = 3;
277  auto vec = makeVec({1500, 3, 3});
278  int pos = 0;
279  const size_t initAppBytesWritten = 500;
280  const size_t appEor = initAppBytesWritten + 1506;
281 
282  sock_->setAppBytesWritten(initAppBytesWritten);
283  EXPECT_FALSE(sock_->isEorTrackingEnabled());
284  sock_->setEorTracking(true);
285  EXPECT_TRUE(sock_->isEorTrackingEnabled());
286 
287  EXPECT_CALL(*(sock_.get()), getRawBytesWritten())
288  // rawBytesWritten after writting initAppBytesWritten + 1500
289  // + some random SSL overhead
290  .WillOnce(Return(3600u))
291  // rawBytesWritten after writting last 6 bytes
292  // + some random SSL overhead
293  .WillOnce(Return(3728u));
294  EXPECT_CALL(*(sock_.get()), sslWriteImpl(_, _, 1500))
295  .WillOnce(Invoke([=, &pos](SSL*, const void* buf, int m) {
296  // the first 1500 does not have the EOR byte
297  sock_->checkEor(0, 0);
298  verifyVec(buf, m, pos);
299  pos += m;
300  return m;
301  }));
302  EXPECT_CALL(*(sock_.get()), sslWriteImpl(_, _, 6))
303  .WillOnce(Invoke([=, &pos](SSL*, const void* buf, int m) {
304  sock_->checkEor(appEor, 3600 + m);
305  verifyVec(buf, m, pos);
306  pos += m;
307  return m;
308  }));
309 
310  uint32_t countWritten = 0;
311  uint32_t partialWritten = 0;
312  sock_->testPerformWrite(
313  vec.get(), n, WriteFlags::EOR, &countWritten, &partialWritten);
314  EXPECT_EQ(countWritten, n);
315  EXPECT_EQ(partialWritten, 0);
316  sock_->checkEor(0, 0);
317 }
318 
319 // coalescing with left over at the last chunk
320 // WriteFlags::EOR turned on
321 TEST_F(AsyncSSLSocketWriteTest, write_with_eor2) {
322  int n = 3;
323  auto vec = makeVec({600, 600, 600});
324  int pos = 0;
325  const size_t initAppBytesWritten = 500;
326  const size_t appEor = initAppBytesWritten + 1800;
327 
328  sock_->setAppBytesWritten(initAppBytesWritten);
329  sock_->setEorTracking(true);
330 
331  EXPECT_CALL(*(sock_.get()), getRawBytesWritten())
332  // rawBytesWritten after writting initAppBytesWritten + 1500 bytes
333  // + some random SSL overhead
334  .WillOnce(Return(3600))
335  // rawBytesWritten after writting last 300 bytes
336  // + some random SSL overhead
337  .WillOnce(Return(4100));
338  EXPECT_CALL(*(sock_.get()), sslWriteImpl(_, _, 1500))
339  .WillOnce(Invoke([=, &pos](SSL*, const void* buf, int m) {
340  // the first 1500 does not have the EOR byte
341  sock_->checkEor(0, 0);
342  verifyVec(buf, m, pos);
343  pos += m;
344  return m;
345  }));
346  EXPECT_CALL(*(sock_.get()), sslWriteImpl(_, _, 300))
347  .WillOnce(Invoke([=, &pos](SSL*, const void* buf, int m) {
348  sock_->checkEor(appEor, 3600 + m);
349  verifyVec(buf, m, pos);
350  pos += m;
351  return m;
352  }));
353 
354  uint32_t countWritten = 0;
355  uint32_t partialWritten = 0;
356  sock_->testPerformWrite(
357  vec.get(), n, WriteFlags::EOR, &countWritten, &partialWritten);
358  EXPECT_EQ(countWritten, n);
359  EXPECT_EQ(partialWritten, 0);
360  sock_->checkEor(0, 0);
361 }
362 
363 // WriteFlags::EOR set
364 // One buf in iovec
365 // Partial write at 1000-th byte
366 TEST_F(AsyncSSLSocketWriteTest, write_with_eor3) {
367  int n = 1;
368  auto vec = makeVec({1600});
369  int pos = 0;
370  static constexpr size_t initAppBytesWritten = 500;
371  static constexpr size_t appEor = initAppBytesWritten + 1600;
372 
373  sock_->setAppBytesWritten(initAppBytesWritten);
374  sock_->setEorTracking(true);
375 
376  EXPECT_CALL(*(sock_.get()), getRawBytesWritten())
377  // rawBytesWritten after the initAppBytesWritten
378  // + some random SSL overhead
379  .WillOnce(Return(2000))
380  // rawBytesWritten after the initAppBytesWritten + 1000 (with 100
381  // overhead)
382  // + some random SSL overhead
383  .WillOnce(Return(3100));
384  EXPECT_CALL(*(sock_.get()), sslWriteImpl(_, _, 1600))
385  .WillOnce(Invoke([this, &pos](SSL*, const void* buf, int m) {
386  sock_->checkEor(appEor, 2000 + m);
387  verifyVec(buf, m, pos);
388  pos += 1000;
389  return 1000;
390  }));
391 
392  uint32_t countWritten = 0;
393  uint32_t partialWritten = 0;
394  sock_->testPerformWrite(
395  vec.get(), n, WriteFlags::EOR, &countWritten, &partialWritten);
396  EXPECT_EQ(countWritten, 0);
397  EXPECT_EQ(partialWritten, 1000);
398  sock_->checkEor(appEor, 2000 + 1600);
399  consumeVec(vec.get(), countWritten, partialWritten);
400 
401  EXPECT_CALL(*(sock_.get()), getRawBytesWritten())
402  .WillOnce(Return(3100))
403  .WillOnce(Return(3800));
404  EXPECT_CALL(*(sock_.get()), sslWriteImpl(_, _, 600))
405  .WillOnce(Invoke([this, &pos](SSL*, const void* buf, int m) {
406  sock_->checkEor(appEor, 3100 + m);
407  verifyVec(buf, m, pos);
408  pos += m;
409  return m;
410  }));
411  sock_->testPerformWrite(
412  vec.get() + countWritten,
413  n - countWritten,
414  WriteFlags::EOR,
415  &countWritten,
416  &partialWritten);
417  EXPECT_EQ(countWritten, n);
418  EXPECT_EQ(partialWritten, 0);
419  sock_->checkEor(0, 0);
420 }
421 
422 } // namespace folly
std::unique_ptr< iovec[]> makeVec(std::vector< uint32_t > sizes)
void consumeVec(iovec *vec, uint32_t countWritten, uint32_t partialWritten)
flags
Definition: http_parser.h:127
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
TEST_F(TestInfoTest, Names)
MockAsyncSSLSocket(const std::shared_ptr< SSLContext > &ctx, EventBase *evb)
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
std::shared_ptr< MockAsyncSSLSocket > sock_
#define MOCK_METHOD3(m,...)
WriteResult testPerformWrite(const iovec *vec, uint32_t count, WriteFlags flags, uint32_t *countWritten, uint32_t *partialWritten)
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
const int sizes[]
PolymorphicAction< internal::InvokeAction< FunctionImpl > > Invoke(FunctionImpl function_impl)
static map< string, int > m
AsyncSocket::UniquePtr sock_
Definition: Traits.h:588
void checkEor(size_t appEor, size_t rawEor)
std::shared_ptr< SSLContext > sslContext_
int * count
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
const char * string
Definition: Conv.cpp:212
#define MOCK_CONST_METHOD0(m,...)
vector< string > vec
Definition: StringTest.cpp:35
#define EXPECT_CALL(obj, call)
const internal::AnythingMatcher _
static std::shared_ptr< MockAsyncSSLSocket > newSocket(const std::shared_ptr< SSLContext > &ctx, EventBase *evb)
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
void verifyVec(const void *buf, int n, int pos)
internal::ReturnAction< R > Return(R value)