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