Source code

Revision control

Other Tools

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