LCOV - code coverage report
Current view: top level - netwerk/base - TCPFastOpenLayer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 149 247 60.3 %
Date: 2017-07-14 16:53:18 Functions: 14 15 93.3 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.13