Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/base/TCPFastOpenLayer.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim:set ts=2 sw=2 sts=2 et cindent: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "TCPFastOpenLayer.h"
8
#include "nsSocketTransportService2.h"
9
#include "prmem.h"
10
#include "prio.h"
11
12
namespace mozilla {
13
namespace net {
14
15
static PRDescIdentity sTCPFastOpenLayerIdentity;
16
static PRIOMethods    sTCPFastOpenLayerMethods;
17
static PRIOMethods   *sTCPFastOpenLayerMethodsPtr = nullptr;
18
19
0
#define TFO_MAX_PACKET_SIZE_IPV4 1460
20
0
#define TFO_MAX_PACKET_SIZE_IPV6 1440
21
0
#define TFO_TLS_RECORD_HEADER_SIZE 22
22
23
/**
24
 *  For the TCP Fast Open it is necessary to send all data that can fit into the
25
 *  first packet on a single sendto function call. Consecutive calls will not
26
 *  have an effect. Therefore  TCPFastOpenLayer will collect some data before
27
 *  calling sendto. Necko and nss will call PR_Write multiple times with small
28
 *  amount of  data.
29
 *  TCPFastOpenLayer has 4 states:
30
 *    WAITING_FOR_CONNECT:
31
 *      This is before connect is call. A call of recv, send or getpeername will
32
 *      return PR_NOT_CONNECTED_ERROR. After connect is call the state transfers
33
 *      into COLLECT_DATA_FOR_FIRST_PACKET.
34
 *
35
 *    COLLECT_DATA_FOR_FIRST_PACKET:
36
 *      In this state all data received by send function calls will be stored in
37
 *      a buffer. If transaction do not have any more data ready to be sent or
38
 *      the buffer is full, TCPFastOpenFinish is call. TCPFastOpenFinish sends
39
 *      the collected data using sendto function and the state transfers to
40
 *      WAITING_FOR_CONNECTCONTINUE. If an error occurs during sendto, the error
41
 *      is reported by the TCPFastOpenFinish return values. nsSocketTransfer is
42
 *      the only caller of TCPFastOpenFinish; it knows how to interpreter these
43
 *      errors.
44
 *    WAITING_FOR_CONNECTCONTINUE:
45
 *      connectcontinue transfers from this state to CONNECTED. Any other
46
 *      function (e.g. send, recv) returns PR_WOULD_BLOCK_ERROR.
47
 *    CONNECTED:
48
 *      The size of mFirstPacketBuf is 1440/1460 (RFC7413 recomends that packet
49
 *      does exceeds these sizes). SendTo does not have to consume all buffered
50
 *      data and some data can be still in mFirstPacketBuf. Before sending any
51
 *      new data we need to send the remaining buffered data.
52
 **/
53
54
class TCPFastOpenSecret
55
{
56
public:
57
  TCPFastOpenSecret()
58
    : mState(WAITING_FOR_CONNECT)
59
    , mFirstPacketBufLen(0)
60
    , mCondition(0)
61
0
  {
62
0
    this->mAddr.raw.family = 0;
63
0
    this->mAddr.inet.family = 0;
64
0
    this->mAddr.inet.port = 0;
65
0
    this->mAddr.inet.ip = 0;
66
0
    this->mAddr.ipv6.family = 0;
67
0
    this->mAddr.ipv6.port = 0;
68
0
    this->mAddr.ipv6.flowinfo = 0;
69
0
    this->mAddr.ipv6.scope_id = 0;
70
0
    this->mAddr.local.family = 0;
71
0
  }
72
73
  enum {
74
    CONNECTED,
75
    WAITING_FOR_CONNECTCONTINUE,
76
    COLLECT_DATA_FOR_FIRST_PACKET,
77
    WAITING_FOR_CONNECT,
78
    SOCKET_ERROR_STATE
79
  } mState;
80
  PRNetAddr mAddr;
81
  char mFirstPacketBuf[1460];
82
  uint16_t mFirstPacketBufLen;
83
  PRErrorCode mCondition;
84
};
85
86
static PRStatus
87
TCPFastOpenConnect(PRFileDesc *fd, const PRNetAddr *addr,
88
                   PRIntervalTime timeout)
89
0
{
90
0
  MOZ_RELEASE_ASSERT(fd->identity == sTCPFastOpenLayerIdentity);
91
0
  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
92
0
93
0
  TCPFastOpenSecret *secret = reinterpret_cast<TCPFastOpenSecret *>(fd->secret);
94
0
95
0
  SOCKET_LOG(("TCPFastOpenConnect state=%d.\n", secret->mState));
96
0
97
0
  if (secret->mState != TCPFastOpenSecret::WAITING_FOR_CONNECT) {
98
0
    PR_SetError(PR_IS_CONNECTED_ERROR, 0);
99
0
    return PR_FAILURE;
100
0
  }
101
0
102
0
  // Remember the address. It will be used for sendto or connect later.
103
0
  memcpy(&secret->mAddr, addr, sizeof(secret->mAddr));
104
0
  secret->mState = TCPFastOpenSecret::COLLECT_DATA_FOR_FIRST_PACKET;
105
0
106
0
  return PR_SUCCESS;
107
0
}
108
109
static PRInt32
110
TCPFastOpenSend(PRFileDesc *fd, const void *buf, PRInt32 amount,
111
                PRIntn flags, PRIntervalTime timeout)
112
0
{
113
0
  MOZ_RELEASE_ASSERT(fd->identity == sTCPFastOpenLayerIdentity);
114
0
  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
115
0
116
0
  TCPFastOpenSecret *secret = reinterpret_cast<TCPFastOpenSecret *>(fd->secret);
117
0
118
0
  SOCKET_LOG(("TCPFastOpenSend state=%d.\n", secret->mState));
119
0
120
0
  switch(secret->mState) {
121
0
  case TCPFastOpenSecret::CONNECTED:
122
0
    // Before sending new data we need to drain the data collected during tfo.
123
0
    if (secret->mFirstPacketBufLen) {
124
0
      SOCKET_LOG(("TCPFastOpenSend - %d bytes to drain from "
125
0
                  "mFirstPacketBufLen.\n",
126
0
                  secret->mFirstPacketBufLen ));
127
0
      PRInt32 rv = (fd->lower->methods->send)(fd->lower,
128
0
                                              secret->mFirstPacketBuf,
129
0
                                              secret->mFirstPacketBufLen,
130
0
                                              0, // flags
131
0
                                              PR_INTERVAL_NO_WAIT);
132
0
      if (rv <= 0) {
133
0
        return rv;
134
0
      }
135
0
      secret->mFirstPacketBufLen -= rv;
136
0
      if (secret->mFirstPacketBufLen) {
137
0
        memmove(secret->mFirstPacketBuf,
138
0
                secret->mFirstPacketBuf + rv,
139
0
                secret->mFirstPacketBufLen);
140
0
141
0
        PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
142
0
        return PR_FAILURE;
143
0
      } // if we drained the buffer we can fall through this checks and call
144
0
        // send for the new data
145
0
    }
146
0
    SOCKET_LOG(("TCPFastOpenSend sending new data.\n"));
147
0
    return (fd->lower->methods->send)(fd->lower, buf, amount, flags, timeout);
148
0
  case TCPFastOpenSecret::WAITING_FOR_CONNECTCONTINUE:
149
0
    PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
150
0
    return -1;
151
0
  case TCPFastOpenSecret::COLLECT_DATA_FOR_FIRST_PACKET:
152
0
    {
153
0
      int32_t toSend =
154
0
        (secret->mAddr.raw.family == PR_AF_INET) ? TFO_MAX_PACKET_SIZE_IPV4
155
0
                                              : TFO_MAX_PACKET_SIZE_IPV6;
156
0
      MOZ_ASSERT(secret->mFirstPacketBufLen <= toSend);
157
0
      toSend -= secret->mFirstPacketBufLen;
158
0
159
0
      SOCKET_LOG(("TCPFastOpenSend: amount of data in the buffer=%d; the amount"
160
0
                  " of additional data that can be stored=%d.\n",
161
0
                  secret->mFirstPacketBufLen, toSend));
162
0
163
0
      if (!toSend) {
164
0
        PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
165
0
        return -1;
166
0
      }
167
0
168
0
      toSend = (toSend > amount) ? amount : toSend;
169
0
      memcpy(secret->mFirstPacketBuf + secret->mFirstPacketBufLen, buf, toSend);
170
0
      secret->mFirstPacketBufLen += toSend;
171
0
      return toSend;
172
0
    }
173
0
  case TCPFastOpenSecret::WAITING_FOR_CONNECT:
174
0
    PR_SetError(PR_NOT_CONNECTED_ERROR, 0);
175
0
    return -1;
176
0
  case TCPFastOpenSecret::SOCKET_ERROR_STATE:
177
0
    PR_SetError(secret->mCondition, 0);
178
0
    return -1;
179
0
  }
180
0
  PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
181
0
  return PR_FAILURE;
182
0
}
183
184
static PRInt32
185
TCPFastOpenWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
186
0
{
187
0
  return TCPFastOpenSend(fd, buf, amount, 0, PR_INTERVAL_NO_WAIT);
188
0
}
189
190
static PRInt32
191
TCPFastOpenRecv(PRFileDesc *fd, void *buf, PRInt32 amount,
192
                PRIntn flags, PRIntervalTime timeout)
193
0
{
194
0
  MOZ_RELEASE_ASSERT(fd->identity == sTCPFastOpenLayerIdentity);
195
0
196
0
  TCPFastOpenSecret *secret = reinterpret_cast<TCPFastOpenSecret *>(fd->secret);
197
0
198
0
  PRInt32 rv = -1;
199
0
  switch(secret->mState) {
200
0
  case TCPFastOpenSecret::CONNECTED:
201
0
202
0
    if (secret->mFirstPacketBufLen) {
203
0
      // TLS will not call write before receiving data from a server, therefore
204
0
      // we need to force sending buffered data even during recv call. Otherwise
205
0
      // It can come to a deadlock (clients waits for response, but the request
206
0
      // is sitting in mFirstPacketBufLen).
207
0
      SOCKET_LOG(("TCPFastOpenRevc - %d bytes to drain from mFirstPacketBuf.\n",
208
0
                  secret->mFirstPacketBufLen ));
209
0
      PRInt32 rv = (fd->lower->methods->send)(fd->lower,
210
0
                                              secret->mFirstPacketBuf,
211
0
                                              secret->mFirstPacketBufLen,
212
0
                                              0, // flags
213
0
                                              PR_INTERVAL_NO_WAIT);
214
0
      if (rv <= 0) {
215
0
        return rv;
216
0
      }
217
0
      secret->mFirstPacketBufLen -= rv;
218
0
      if (secret->mFirstPacketBufLen) {
219
0
        memmove(secret->mFirstPacketBuf,
220
0
                secret->mFirstPacketBuf + rv,
221
0
                secret->mFirstPacketBufLen);
222
0
      }
223
0
    }
224
0
    rv = (fd->lower->methods->recv)(fd->lower, buf, amount, flags, timeout);
225
0
    break;
226
0
  case TCPFastOpenSecret::WAITING_FOR_CONNECTCONTINUE:
227
0
  case TCPFastOpenSecret::COLLECT_DATA_FOR_FIRST_PACKET:
228
0
    PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
229
0
    break;
230
0
  case TCPFastOpenSecret::WAITING_FOR_CONNECT:
231
0
    PR_SetError(PR_NOT_CONNECTED_ERROR, 0);
232
0
    break;
233
0
  case TCPFastOpenSecret::SOCKET_ERROR_STATE:
234
0
    PR_SetError(secret->mCondition, 0);
235
0
  }
236
0
  return rv;
237
0
}
238
239
static PRInt32
240
TCPFastOpenRead(PRFileDesc *fd, void *buf, PRInt32 amount)
241
0
{
242
0
  return TCPFastOpenRecv(fd, buf, amount , 0, PR_INTERVAL_NO_WAIT);
243
0
}
244
245
static PRStatus
246
TCPFastOpenConnectContinue(PRFileDesc *fd, PRInt16 out_flags)
247
0
{
248
0
  MOZ_RELEASE_ASSERT(fd->identity == sTCPFastOpenLayerIdentity);
249
0
250
0
  TCPFastOpenSecret *secret = reinterpret_cast<TCPFastOpenSecret *>(fd->secret);
251
0
252
0
  PRStatus rv = PR_FAILURE;
253
0
  switch(secret->mState) {
254
0
  case TCPFastOpenSecret::CONNECTED:
255
0
    rv = PR_SUCCESS;
256
0
    break;
257
0
  case TCPFastOpenSecret::WAITING_FOR_CONNECT:
258
0
  case TCPFastOpenSecret::COLLECT_DATA_FOR_FIRST_PACKET:
259
0
    PR_SetError(PR_NOT_CONNECTED_ERROR, 0);
260
0
    rv = PR_FAILURE;
261
0
    break;
262
0
  case TCPFastOpenSecret::WAITING_FOR_CONNECTCONTINUE:
263
0
    rv = (fd->lower->methods->connectcontinue)(fd->lower, out_flags);
264
0
265
0
    SOCKET_LOG(("TCPFastOpenConnectContinue result=%d.\n", rv));
266
0
    secret->mState = TCPFastOpenSecret::CONNECTED;
267
0
    break;
268
0
  case TCPFastOpenSecret::SOCKET_ERROR_STATE:
269
0
    PR_SetError(secret->mCondition, 0);
270
0
    rv = PR_FAILURE;
271
0
  }
272
0
  return rv;
273
0
}
274
275
static PRStatus
276
TCPFastOpenClose(PRFileDesc *fd)
277
0
{
278
0
  if (!fd) {
279
0
    return PR_FAILURE;
280
0
  }
281
0
282
0
  PRFileDesc* layer = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
283
0
284
0
  MOZ_RELEASE_ASSERT(layer &&
285
0
                     layer->identity == sTCPFastOpenLayerIdentity,
286
0
                     "TCP Fast Open Layer not on top of stack");
287
0
288
0
  TCPFastOpenSecret *secret = reinterpret_cast<TCPFastOpenSecret *>(layer->secret);
289
0
  layer->secret = nullptr;
290
0
  layer->dtor(layer);
291
0
  delete secret;
292
0
  return fd->methods->close(fd);
293
0
}
294
295
static PRStatus
296
TCPFastOpenGetpeername (PRFileDesc *fd, PRNetAddr *addr)
297
0
{
298
0
  MOZ_RELEASE_ASSERT(fd);
299
0
  MOZ_RELEASE_ASSERT(addr);
300
0
301
0
  MOZ_RELEASE_ASSERT(fd->identity == sTCPFastOpenLayerIdentity);
302
0
303
0
  TCPFastOpenSecret *secret = reinterpret_cast<TCPFastOpenSecret *>(fd->secret);
304
0
  if (secret->mState == TCPFastOpenSecret::WAITING_FOR_CONNECT) {
305
0
    PR_SetError(PR_NOT_CONNECTED_ERROR, 0);
306
0
    return PR_FAILURE;
307
0
  }
308
0
309
0
  memcpy(addr, &secret->mAddr, sizeof(secret->mAddr));
310
0
  return PR_SUCCESS;
311
0
}
312
313
static PRInt16
314
TCPFastOpenPoll(PRFileDesc *fd, PRInt16 how_flags, PRInt16 *p_out_flags)
315
0
{
316
0
  MOZ_RELEASE_ASSERT(fd);
317
0
  MOZ_RELEASE_ASSERT(fd->identity == sTCPFastOpenLayerIdentity);
318
0
319
0
  TCPFastOpenSecret *secret = reinterpret_cast<TCPFastOpenSecret *>(fd->secret);
320
0
  if (secret->mFirstPacketBufLen) {
321
0
    how_flags |= PR_POLL_WRITE;
322
0
  }
323
0
324
0
  return fd->lower->methods->poll(fd->lower, how_flags, p_out_flags);
325
0
}
326
327
nsresult
328
AttachTCPFastOpenIOLayer(PRFileDesc *fd)
329
0
{
330
0
  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
331
0
332
0
  if (!sTCPFastOpenLayerMethodsPtr) {
333
0
    sTCPFastOpenLayerIdentity = PR_GetUniqueIdentity("TCPFastOpen Layer");
334
0
    sTCPFastOpenLayerMethods = *PR_GetDefaultIOMethods();
335
0
    sTCPFastOpenLayerMethods.connect = TCPFastOpenConnect;
336
0
    sTCPFastOpenLayerMethods.send = TCPFastOpenSend;
337
0
    sTCPFastOpenLayerMethods.write = TCPFastOpenWrite;
338
0
    sTCPFastOpenLayerMethods.recv = TCPFastOpenRecv;
339
0
    sTCPFastOpenLayerMethods.read = TCPFastOpenRead;
340
0
    sTCPFastOpenLayerMethods.connectcontinue = TCPFastOpenConnectContinue;
341
0
    sTCPFastOpenLayerMethods.close = TCPFastOpenClose;
342
0
    sTCPFastOpenLayerMethods.getpeername = TCPFastOpenGetpeername;
343
0
    sTCPFastOpenLayerMethods.poll = TCPFastOpenPoll;
344
0
    sTCPFastOpenLayerMethodsPtr = &sTCPFastOpenLayerMethods;
345
0
  }
346
0
347
0
  PRFileDesc *layer = PR_CreateIOLayerStub(sTCPFastOpenLayerIdentity,
348
0
                                           sTCPFastOpenLayerMethodsPtr);
349
0
350
0
  if (!layer) {
351
0
    return NS_ERROR_FAILURE;
352
0
  }
353
0
354
0
  TCPFastOpenSecret *secret = new TCPFastOpenSecret();
355
0
356
0
  layer->secret = reinterpret_cast<PRFilePrivate *>(secret);
357
0
358
0
  PRStatus status = PR_PushIOLayer(fd, PR_NSPR_IO_LAYER, layer);
359
0
360
0
  if (status == PR_FAILURE) {
361
0
    delete secret;
362
0
    PR_Free(layer); // PR_CreateIOLayerStub() uses PR_Malloc().
363
0
    return NS_ERROR_FAILURE;
364
0
  }
365
0
  return NS_OK;
366
0
}
367
368
void
369
TCPFastOpenFinish(PRFileDesc *fd, PRErrorCode &err,
370
                  bool &fastOpenNotSupported, uint8_t &tfoStatus)
371
0
{
372
0
  PRFileDesc *tfoFd = PR_GetIdentitiesLayer(fd, sTCPFastOpenLayerIdentity);
373
0
  MOZ_RELEASE_ASSERT(tfoFd);
374
0
  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
375
0
376
0
  TCPFastOpenSecret *secret = reinterpret_cast<TCPFastOpenSecret *>(tfoFd->secret);
377
0
378
0
  MOZ_ASSERT(secret->mState == TCPFastOpenSecret::COLLECT_DATA_FOR_FIRST_PACKET);
379
0
380
0
  fastOpenNotSupported = false;
381
0
  tfoStatus = TFO_NOT_TRIED;
382
0
  PRErrorCode result = 0;
383
0
384
0
  // If we do not have data to send with syn packet or nspr version does not
385
0
  // have sendto implemented we will call normal connect.
386
0
  // If sendto is not implemented it points to _PR_InvalidInt, therefore we
387
0
  // check if sendto != _PR_InvalidInt. _PR_InvalidInt is exposed so we use
388
0
  // reserved_fn_0 which also points to _PR_InvalidInt.
389
0
  if (!secret->mFirstPacketBufLen ||
390
0
      (tfoFd->lower->methods->sendto == (PRSendtoFN)tfoFd->lower->methods->reserved_fn_0)) {
391
0
    // Because of the way our nsHttpTransaction dispatch work, it can happened
392
0
    // that data has not been written into the socket.
393
0
    // In this case we can just call connect.
394
0
    PRInt32 rv = (tfoFd->lower->methods->connect)(tfoFd->lower, &secret->mAddr,
395
0
                                                  PR_INTERVAL_NO_WAIT);
396
0
    if (rv == PR_SUCCESS) {
397
0
      result = PR_IS_CONNECTED_ERROR;
398
0
    } else {
399
0
      result = PR_GetError();
400
0
    }
401
0
    if (tfoFd->lower->methods->sendto == (PRSendtoFN)tfoFd->lower->methods->reserved_fn_0) {
402
0
        // sendto is not implemented, it is equal to _PR_InvalidInt!
403
0
        // We will disable Fast Open.
404
0
        SOCKET_LOG(("TCPFastOpenFinish - sendto not implemented.\n"));
405
0
        fastOpenNotSupported = true;
406
0
        tfoStatus = TFO_DISABLED;
407
0
    }
408
0
  } else {
409
0
    // We have some data ready in the buffer we will send it with the syn
410
0
    // packet.
411
0
    PRInt32 rv = (tfoFd->lower->methods->sendto)(tfoFd->lower,
412
0
                                                 secret->mFirstPacketBuf,
413
0
                                                 secret->mFirstPacketBufLen,
414
0
                                                 0, //flags
415
0
                                                 &secret->mAddr,
416
0
                                                 PR_INTERVAL_NO_WAIT);
417
0
418
0
    SOCKET_LOG(("TCPFastOpenFinish - sendto result=%d.\n", rv));
419
0
    if (rv > 0) {
420
0
      result = PR_IN_PROGRESS_ERROR;
421
0
      secret->mFirstPacketBufLen -= rv;
422
0
      if (secret->mFirstPacketBufLen) {
423
0
        memmove(secret->mFirstPacketBuf,
424
0
                secret->mFirstPacketBuf + rv,
425
0
                secret->mFirstPacketBufLen);
426
0
      }
427
0
      tfoStatus = TFO_DATA_SENT;
428
0
    } else {
429
0
      result = PR_GetError();
430
0
      SOCKET_LOG(("TCPFastOpenFinish - sendto error=%d.\n", result));
431
0
432
0
      if (result == PR_NOT_TCP_SOCKET_ERROR) { // SendTo will return PR_NOT_TCP_SOCKET_ERROR if TCP Fast Open is turned off on Linux.
433
0
        // We can call connect again.
434
0
        fastOpenNotSupported = true;
435
0
        rv = (tfoFd->lower->methods->connect)(tfoFd->lower, &secret->mAddr,
436
0
                                              PR_INTERVAL_NO_WAIT);
437
0
438
0
        if (rv == PR_SUCCESS) {
439
0
          result = PR_IS_CONNECTED_ERROR;
440
0
        } else {
441
0
          result = PR_GetError();
442
0
        }
443
0
        tfoStatus = TFO_DISABLED;
444
0
      } else {
445
0
        tfoStatus = TFO_TRIED;
446
0
      }
447
0
    }
448
0
  }
449
0
450
0
  if (result == PR_IN_PROGRESS_ERROR) {
451
0
    secret->mState = TCPFastOpenSecret::WAITING_FOR_CONNECTCONTINUE;
452
0
  } else {
453
0
    // If the error is not PR_IN_PROGRESS_ERROR, change the state to CONNECT so
454
0
    // that recv/send can perform recv/send on the next lower layer and pick up
455
0
    // the real error. This is really important!
456
0
    // The result can also be PR_IS_CONNECTED_ERROR, that should change the
457
0
    // state to CONNECT anyway.
458
0
    secret->mState = TCPFastOpenSecret::CONNECTED;
459
0
  }
460
0
  err = result;
461
0
}
462
463
/* This function returns the size of the remaining free space in the
464
 * first_packet_buffer. This will be used by transactions with a tls layer. For
465
 * other transactions it is not necessary. The tls transactions make a tls
466
 * record before writing to this layer and if the record is too big the part
467
 * that does not have place in the mFirstPacketBuf will be saved on the tls
468
 * layer. During TFO we cannot send more than TFO_MAX_PACKET_SIZE_IPV4/6 bytes,
469
 * so if we have a big tls record, this record is encrypted with 0RTT key,
470
 * tls-early-data can be rejected and than we still need to send the rest of the
471
 * record.
472
 */
473
int32_t
474
TCPFastOpenGetBufferSizeLeft(PRFileDesc *fd)
475
0
{
476
0
  PRFileDesc *tfoFd = PR_GetIdentitiesLayer(fd, sTCPFastOpenLayerIdentity);
477
0
  MOZ_RELEASE_ASSERT(tfoFd);
478
0
  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
479
0
480
0
  TCPFastOpenSecret *secret = reinterpret_cast<TCPFastOpenSecret *>(tfoFd->secret);
481
0
482
0
  if (secret->mState != TCPFastOpenSecret::COLLECT_DATA_FOR_FIRST_PACKET) {
483
0
    return 0;
484
0
  }
485
0
486
0
  int32_t sizeLeft =
487
0
    (secret->mAddr.raw.family == PR_AF_INET) ? TFO_MAX_PACKET_SIZE_IPV4
488
0
                                             : TFO_MAX_PACKET_SIZE_IPV6;
489
0
  MOZ_ASSERT(secret->mFirstPacketBufLen <= sizeLeft);
490
0
  sizeLeft -= secret->mFirstPacketBufLen;
491
0
492
0
  SOCKET_LOG(("TCPFastOpenGetBufferSizeLeft=%d.\n", sizeLeft));
493
0
494
0
  return (sizeLeft > TFO_TLS_RECORD_HEADER_SIZE) ?
495
0
    sizeLeft - TFO_TLS_RECORD_HEADER_SIZE : 0;
496
0
}
497
498
bool
499
TCPFastOpenGetCurrentBufferSize(PRFileDesc *fd)
500
0
{
501
0
  PRFileDesc *tfoFd = PR_GetIdentitiesLayer(fd, sTCPFastOpenLayerIdentity);
502
0
  MOZ_RELEASE_ASSERT(tfoFd);
503
0
  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
504
0
505
0
  TCPFastOpenSecret *secret = reinterpret_cast<TCPFastOpenSecret *>(tfoFd->secret);
506
0
507
0
  return secret->mFirstPacketBufLen;
508
0
}
509
510
bool
511
TCPFastOpenFlushBuffer(PRFileDesc *fd)
512
0
{
513
0
  PRFileDesc *tfoFd = PR_GetIdentitiesLayer(fd, sTCPFastOpenLayerIdentity);
514
0
  MOZ_RELEASE_ASSERT(tfoFd);
515
0
  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
516
0
517
0
  TCPFastOpenSecret *secret = reinterpret_cast<TCPFastOpenSecret *>(tfoFd->secret);
518
0
  MOZ_ASSERT(secret->mState == TCPFastOpenSecret::CONNECTED);
519
0
520
0
  if (secret->mFirstPacketBufLen) {
521
0
    SOCKET_LOG(("TCPFastOpenFlushBuffer - %d bytes to drain from "
522
0
                "mFirstPacketBufLen.\n",
523
0
                secret->mFirstPacketBufLen ));
524
0
    PRInt32 rv = (tfoFd->lower->methods->send)(tfoFd->lower,
525
0
                                               secret->mFirstPacketBuf,
526
0
                                               secret->mFirstPacketBufLen,
527
0
                                               0, // flags
528
0
                                               PR_INTERVAL_NO_WAIT);
529
0
    if (rv <= 0) {
530
0
      PRErrorCode err = PR_GetError();
531
0
      if (err == PR_WOULD_BLOCK_ERROR) {
532
0
        // We still need to send this data.
533
0
        return true;
534
0
      }
535
0
      // There is an error, let nsSocketTransport pick it up properly.
536
0
      secret->mCondition = err;
537
0
      secret->mState = TCPFastOpenSecret::SOCKET_ERROR_STATE;
538
0
      return false;
539
0
    }
540
0
541
0
    secret->mFirstPacketBufLen -= rv;
542
0
    if (secret->mFirstPacketBufLen) {
543
0
      memmove(secret->mFirstPacketBuf,
544
0
              secret->mFirstPacketBuf + rv,
545
0
              secret->mFirstPacketBufLen);
546
0
    }
547
0
  }
548
0
  return secret->mFirstPacketBufLen;
549
0
}
550
551
}
552
}