tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

priometh.c (16388B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 
      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 #include "primpl.h"
      7 
      8 #include <string.h>
      9 
     10 /*****************************************************************************/
     11 /************************** Invalid I/O method object ************************/
     12 /*****************************************************************************/
     13 PRIOMethods _pr_faulty_methods = {(PRDescType)0,
     14                                  (PRCloseFN)_PR_InvalidStatus,
     15                                  (PRReadFN)_PR_InvalidInt,
     16                                  (PRWriteFN)_PR_InvalidInt,
     17                                  (PRAvailableFN)_PR_InvalidInt,
     18                                  (PRAvailable64FN)_PR_InvalidInt64,
     19                                  (PRFsyncFN)_PR_InvalidStatus,
     20                                  (PRSeekFN)_PR_InvalidInt,
     21                                  (PRSeek64FN)_PR_InvalidInt64,
     22                                  (PRFileInfoFN)_PR_InvalidStatus,
     23                                  (PRFileInfo64FN)_PR_InvalidStatus,
     24                                  (PRWritevFN)_PR_InvalidInt,
     25                                  (PRConnectFN)_PR_InvalidStatus,
     26                                  (PRAcceptFN)_PR_InvalidDesc,
     27                                  (PRBindFN)_PR_InvalidStatus,
     28                                  (PRListenFN)_PR_InvalidStatus,
     29                                  (PRShutdownFN)_PR_InvalidStatus,
     30                                  (PRRecvFN)_PR_InvalidInt,
     31                                  (PRSendFN)_PR_InvalidInt,
     32                                  (PRRecvfromFN)_PR_InvalidInt,
     33                                  (PRSendtoFN)_PR_InvalidInt,
     34                                  (PRPollFN)_PR_InvalidInt16,
     35                                  (PRAcceptreadFN)_PR_InvalidInt,
     36                                  (PRTransmitfileFN)_PR_InvalidInt,
     37                                  (PRGetsocknameFN)_PR_InvalidStatus,
     38                                  (PRGetpeernameFN)_PR_InvalidStatus,
     39                                  (PRReservedFN)_PR_InvalidInt,
     40                                  (PRReservedFN)_PR_InvalidInt,
     41                                  (PRGetsocketoptionFN)_PR_InvalidStatus,
     42                                  (PRSetsocketoptionFN)_PR_InvalidStatus,
     43                                  (PRSendfileFN)_PR_InvalidInt,
     44                                  (PRConnectcontinueFN)_PR_InvalidStatus,
     45                                  (PRReservedFN)_PR_InvalidInt,
     46                                  (PRReservedFN)_PR_InvalidInt,
     47                                  (PRReservedFN)_PR_InvalidInt,
     48                                  (PRReservedFN)_PR_InvalidInt};
     49 
     50 PRIntn _PR_InvalidInt(void) {
     51  PR_NOT_REACHED("I/O method is invalid");
     52  PR_SetError(PR_INVALID_METHOD_ERROR, 0);
     53  return -1;
     54 } /* _PR_InvalidInt */
     55 
     56 PRInt16 _PR_InvalidInt16(void) {
     57  PR_NOT_REACHED("I/O method is invalid");
     58  PR_SetError(PR_INVALID_METHOD_ERROR, 0);
     59  return -1;
     60 } /* _PR_InvalidInt */
     61 
     62 PRInt64 _PR_InvalidInt64(void) {
     63  PRInt64 rv;
     64  LL_I2L(rv, -1);
     65  PR_NOT_REACHED("I/O method is invalid");
     66  PR_SetError(PR_INVALID_METHOD_ERROR, 0);
     67  return rv;
     68 } /* _PR_InvalidInt */
     69 
     70 /*
     71 * An invalid method that returns PRStatus
     72 */
     73 
     74 PRStatus _PR_InvalidStatus(void) {
     75  PR_NOT_REACHED("I/O method is invalid");
     76  PR_SetError(PR_INVALID_METHOD_ERROR, 0);
     77  return PR_FAILURE;
     78 } /* _PR_InvalidDesc */
     79 
     80 /*
     81 * An invalid method that returns a pointer
     82 */
     83 
     84 PRFileDesc* _PR_InvalidDesc(void) {
     85  PR_NOT_REACHED("I/O method is invalid");
     86  PR_SetError(PR_INVALID_METHOD_ERROR, 0);
     87  return NULL;
     88 } /* _PR_InvalidDesc */
     89 
     90 PR_IMPLEMENT(PRDescType) PR_GetDescType(PRFileDesc* file) {
     91  return file->methods->file_type;
     92 }
     93 
     94 PR_IMPLEMENT(PRStatus) PR_Close(PRFileDesc* fd) {
     95  return (fd->methods->close)(fd);
     96 }
     97 
     98 PR_IMPLEMENT(PRInt32) PR_Read(PRFileDesc* fd, void* buf, PRInt32 amount) {
     99  return ((fd->methods->read)(fd, buf, amount));
    100 }
    101 
    102 PR_IMPLEMENT(PRInt32)
    103 PR_Write(PRFileDesc* fd, const void* buf, PRInt32 amount) {
    104  return ((fd->methods->write)(fd, buf, amount));
    105 }
    106 
    107 PR_IMPLEMENT(PRInt32)
    108 PR_Seek(PRFileDesc* fd, PRInt32 offset, PRSeekWhence whence) {
    109  return ((fd->methods->seek)(fd, offset, whence));
    110 }
    111 
    112 PR_IMPLEMENT(PRInt64)
    113 PR_Seek64(PRFileDesc* fd, PRInt64 offset, PRSeekWhence whence) {
    114  return ((fd->methods->seek64)(fd, offset, whence));
    115 }
    116 
    117 PR_IMPLEMENT(PRInt32) PR_Available(PRFileDesc* fd) {
    118  return ((fd->methods->available)(fd));
    119 }
    120 
    121 PR_IMPLEMENT(PRInt64) PR_Available64(PRFileDesc* fd) {
    122  return ((fd->methods->available64)(fd));
    123 }
    124 
    125 PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo(PRFileDesc* fd, PRFileInfo* info) {
    126  return ((fd->methods->fileInfo)(fd, info));
    127 }
    128 
    129 PR_IMPLEMENT(PRStatus)
    130 PR_GetOpenFileInfo64(PRFileDesc* fd, PRFileInfo64* info) {
    131  return ((fd->methods->fileInfo64)(fd, info));
    132 }
    133 
    134 PR_IMPLEMENT(PRStatus) PR_Sync(PRFileDesc* fd) {
    135  return ((fd->methods->fsync)(fd));
    136 }
    137 
    138 PR_IMPLEMENT(PRStatus)
    139 PR_Connect(PRFileDesc* fd, const PRNetAddr* addr, PRIntervalTime timeout) {
    140  return ((fd->methods->connect)(fd, addr, timeout));
    141 }
    142 
    143 PR_IMPLEMENT(PRStatus) PR_ConnectContinue(PRFileDesc* fd, PRInt16 out_flags) {
    144  return ((fd->methods->connectcontinue)(fd, out_flags));
    145 }
    146 
    147 PR_IMPLEMENT(PRFileDesc*)
    148 PR_Accept(PRFileDesc* fd, PRNetAddr* addr, PRIntervalTime timeout) {
    149  return ((fd->methods->accept)(fd, addr, timeout));
    150 }
    151 
    152 PR_IMPLEMENT(PRStatus) PR_Bind(PRFileDesc* fd, const PRNetAddr* addr) {
    153  return ((fd->methods->bind)(fd, addr));
    154 }
    155 
    156 PR_IMPLEMENT(PRStatus) PR_Shutdown(PRFileDesc* fd, PRShutdownHow how) {
    157  return ((fd->methods->shutdown)(fd, how));
    158 }
    159 
    160 PR_IMPLEMENT(PRStatus) PR_Listen(PRFileDesc* fd, PRIntn backlog) {
    161  return ((fd->methods->listen)(fd, backlog));
    162 }
    163 
    164 PR_IMPLEMENT(PRInt32)
    165 PR_Recv(PRFileDesc* fd, void* buf, PRInt32 amount, PRIntn flags,
    166        PRIntervalTime timeout) {
    167  return ((fd->methods->recv)(fd, buf, amount, flags, timeout));
    168 }
    169 
    170 PR_IMPLEMENT(PRInt32)
    171 PR_Send(PRFileDesc* fd, const void* buf, PRInt32 amount, PRIntn flags,
    172        PRIntervalTime timeout) {
    173  return ((fd->methods->send)(fd, buf, amount, flags, timeout));
    174 }
    175 
    176 PR_IMPLEMENT(PRInt32)
    177 PR_Writev(PRFileDesc* fd, const PRIOVec* iov, PRInt32 iov_size,
    178          PRIntervalTime timeout) {
    179  if (iov_size > PR_MAX_IOVECTOR_SIZE) {
    180    PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
    181    return -1;
    182  }
    183  return ((fd->methods->writev)(fd, iov, iov_size, timeout));
    184 }
    185 
    186 PR_IMPLEMENT(PRInt32)
    187 PR_RecvFrom(PRFileDesc* fd, void* buf, PRInt32 amount, PRIntn flags,
    188            PRNetAddr* addr, PRIntervalTime timeout) {
    189  return ((fd->methods->recvfrom)(fd, buf, amount, flags, addr, timeout));
    190 }
    191 
    192 PR_IMPLEMENT(PRInt32)
    193 PR_SendTo(PRFileDesc* fd, const void* buf, PRInt32 amount, PRIntn flags,
    194          const PRNetAddr* addr, PRIntervalTime timeout) {
    195  return ((fd->methods->sendto)(fd, buf, amount, flags, addr, timeout));
    196 }
    197 
    198 PR_IMPLEMENT(PRInt32)
    199 PR_TransmitFile(PRFileDesc* sd, PRFileDesc* fd, const void* hdr, PRInt32 hlen,
    200                PRTransmitFileFlags flags, PRIntervalTime timeout) {
    201  return ((sd->methods->transmitfile)(sd, fd, hdr, hlen, flags, timeout));
    202 }
    203 
    204 PR_IMPLEMENT(PRInt32)
    205 PR_AcceptRead(PRFileDesc* sd, PRFileDesc** nd, PRNetAddr** raddr, void* buf,
    206              PRInt32 amount, PRIntervalTime timeout) {
    207  return ((sd->methods->acceptread)(sd, nd, raddr, buf, amount, timeout));
    208 }
    209 
    210 PR_IMPLEMENT(PRStatus) PR_GetSockName(PRFileDesc* fd, PRNetAddr* addr) {
    211  return ((fd->methods->getsockname)(fd, addr));
    212 }
    213 
    214 PR_IMPLEMENT(PRStatus) PR_GetPeerName(PRFileDesc* fd, PRNetAddr* addr) {
    215  return ((fd->methods->getpeername)(fd, addr));
    216 }
    217 
    218 PR_IMPLEMENT(PRStatus)
    219 PR_GetSocketOption(PRFileDesc* fd, PRSocketOptionData* data) {
    220  return ((fd->methods->getsocketoption)(fd, data));
    221 }
    222 
    223 PR_IMPLEMENT(PRStatus)
    224 PR_SetSocketOption(PRFileDesc* fd, const PRSocketOptionData* data) {
    225  return ((fd->methods->setsocketoption)(fd, data));
    226 }
    227 
    228 PR_IMPLEMENT(PRInt32)
    229 PR_SendFile(PRFileDesc* sd, PRSendFileData* sfd, PRTransmitFileFlags flags,
    230            PRIntervalTime timeout) {
    231  return ((sd->methods->sendfile)(sd, sfd, flags, timeout));
    232 }
    233 
    234 PR_IMPLEMENT(PRInt32)
    235 PR_EmulateAcceptRead(PRFileDesc* sd, PRFileDesc** nd, PRNetAddr** raddr,
    236                     void* buf, PRInt32 amount, PRIntervalTime timeout) {
    237  PRInt32 rv = -1;
    238  PRNetAddr remote;
    239  PRFileDesc* accepted = NULL;
    240 
    241  /*
    242  ** The timeout does not apply to the accept portion of the
    243  ** operation - it waits indefinitely.
    244  */
    245  accepted = PR_Accept(sd, &remote, PR_INTERVAL_NO_TIMEOUT);
    246  if (NULL == accepted) {
    247    return rv;
    248  }
    249 
    250  rv = PR_Recv(accepted, buf, amount, 0, timeout);
    251  if (rv >= 0) {
    252    /* copy the new info out where caller can see it */
    253 #define AMASK ((PRPtrdiff)7) /* mask for alignment of PRNetAddr */
    254    PRPtrdiff aligned = (PRPtrdiff)buf + amount + AMASK;
    255    *raddr = (PRNetAddr*)(aligned & ~AMASK);
    256    memcpy(*raddr, &remote, PR_NETADDR_SIZE(&remote));
    257    *nd = accepted;
    258    return rv;
    259  }
    260 
    261  PR_Close(accepted);
    262  return rv;
    263 }
    264 
    265 /*
    266 * PR_EmulateSendFile
    267 *
    268 *    Send file sfd->fd across socket sd. If header/trailer are specified
    269 *    they are sent before and after the file, respectively.
    270 *
    271 *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
    272 *
    273 *    return number of bytes sent or -1 on error
    274 *
    275 */
    276 
    277 #if defined(XP_UNIX) || defined(WIN32)
    278 
    279 /*
    280 * An implementation based on memory-mapped files
    281 */
    282 
    283 #  define SENDFILE_MMAP_CHUNK (256 * 1024)
    284 
    285 PR_IMPLEMENT(PRInt32)
    286 PR_EmulateSendFile(PRFileDesc* sd, PRSendFileData* sfd,
    287                   PRTransmitFileFlags flags, PRIntervalTime timeout) {
    288  PRInt32 rv, count = 0;
    289  PRInt32 len, file_bytes, index = 0;
    290  PRFileInfo info;
    291  PRIOVec iov[3];
    292  PRFileMap* mapHandle = NULL;
    293  void* addr = (void*)0; /* initialized to some arbitrary value. Keeps compiler
    294                            warnings down. */
    295  PRUint32 file_mmap_offset, alignment;
    296  PRInt64 zero64;
    297  PROffset64 file_mmap_offset64;
    298  PRUint32 addr_offset, mmap_len;
    299 
    300  /* Get file size */
    301  if (PR_SUCCESS != PR_GetOpenFileInfo(sfd->fd, &info)) {
    302    count = -1;
    303    goto done;
    304  }
    305  if (sfd->file_nbytes && (info.size < (sfd->file_offset + sfd->file_nbytes))) {
    306    /*
    307     * there are fewer bytes in file to send than specified
    308     */
    309    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    310    count = -1;
    311    goto done;
    312  }
    313  if (sfd->file_nbytes) {
    314    file_bytes = sfd->file_nbytes;
    315  } else {
    316    file_bytes = info.size - sfd->file_offset;
    317  }
    318 
    319  alignment = PR_GetMemMapAlignment();
    320 
    321  /* number of initial bytes to skip in mmap'd segment */
    322  addr_offset = sfd->file_offset % alignment;
    323 
    324  /* find previous mmap alignment boundary */
    325  file_mmap_offset = sfd->file_offset - addr_offset;
    326 
    327  /*
    328   * If the file is large, mmap and send the file in chunks so as
    329   * to not consume too much virtual address space
    330   */
    331  mmap_len = PR_MIN(file_bytes + addr_offset, SENDFILE_MMAP_CHUNK);
    332  len = mmap_len - addr_offset;
    333 
    334  /*
    335   * Map in (part of) file. Take care of zero-length files.
    336   */
    337  if (len) {
    338    LL_I2L(zero64, 0);
    339    mapHandle = PR_CreateFileMap(sfd->fd, zero64, PR_PROT_READONLY);
    340    if (!mapHandle) {
    341      count = -1;
    342      goto done;
    343    }
    344    LL_I2L(file_mmap_offset64, file_mmap_offset);
    345    addr = PR_MemMap(mapHandle, file_mmap_offset64, mmap_len);
    346    if (!addr) {
    347      count = -1;
    348      goto done;
    349    }
    350  }
    351  /*
    352   * send headers first, followed by the file
    353   */
    354  if (sfd->hlen) {
    355    iov[index].iov_base = (char*)sfd->header;
    356    iov[index].iov_len = sfd->hlen;
    357    index++;
    358  }
    359  if (len) {
    360    iov[index].iov_base = (char*)addr + addr_offset;
    361    iov[index].iov_len = len;
    362    index++;
    363  }
    364  if ((file_bytes == len) && (sfd->tlen)) {
    365    /*
    366     * all file data is mapped in; send the trailer too
    367     */
    368    iov[index].iov_base = (char*)sfd->trailer;
    369    iov[index].iov_len = sfd->tlen;
    370    index++;
    371  }
    372  rv = PR_Writev(sd, iov, index, timeout);
    373  if (len) {
    374    PR_MemUnmap(addr, mmap_len);
    375  }
    376  if (rv < 0) {
    377    count = -1;
    378    goto done;
    379  }
    380 
    381  PR_ASSERT(rv == sfd->hlen + len + ((len == file_bytes) ? sfd->tlen : 0));
    382 
    383  file_bytes -= len;
    384  count += rv;
    385  if (!file_bytes) { /* header, file and trailer are sent */
    386    goto done;
    387  }
    388 
    389  /*
    390   * send remaining bytes of the file, if any
    391   */
    392  len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
    393  while (len > 0) {
    394    /*
    395     * Map in (part of) file
    396     */
    397    file_mmap_offset = sfd->file_offset + count - sfd->hlen;
    398    PR_ASSERT((file_mmap_offset % alignment) == 0);
    399 
    400    LL_I2L(file_mmap_offset64, file_mmap_offset);
    401    addr = PR_MemMap(mapHandle, file_mmap_offset64, len);
    402    if (!addr) {
    403      count = -1;
    404      goto done;
    405    }
    406    rv = PR_Send(sd, addr, len, 0, timeout);
    407    PR_MemUnmap(addr, len);
    408    if (rv < 0) {
    409      count = -1;
    410      goto done;
    411    }
    412 
    413    PR_ASSERT(rv == len);
    414    file_bytes -= rv;
    415    count += rv;
    416    len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
    417  }
    418  PR_ASSERT(0 == file_bytes);
    419  if (sfd->tlen) {
    420    rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
    421    if (rv >= 0) {
    422      PR_ASSERT(rv == sfd->tlen);
    423      count += rv;
    424    } else {
    425      count = -1;
    426    }
    427  }
    428 done:
    429  if (mapHandle) {
    430    PR_CloseFileMap(mapHandle);
    431  }
    432  if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) {
    433    PR_Close(sd);
    434  }
    435  return count;
    436 }
    437 
    438 #else
    439 
    440 PR_IMPLEMENT(PRInt32)
    441 PR_EmulateSendFile(PRFileDesc* sd, PRSendFileData* sfd,
    442                   PRTransmitFileFlags flags, PRIntervalTime timeout) {
    443  PRInt32 rv, count = 0;
    444  PRInt32 rlen;
    445  const void* buffer;
    446  PRInt32 buflen;
    447  PRInt32 sendbytes, readbytes;
    448  char* buf;
    449 
    450 #  define _SENDFILE_BUFSIZE (16 * 1024)
    451 
    452  buf = (char*)PR_MALLOC(_SENDFILE_BUFSIZE);
    453  if (buf == NULL) {
    454    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    455    return -1;
    456  }
    457 
    458  /*
    459   * send header first
    460   */
    461  buflen = sfd->hlen;
    462  buffer = sfd->header;
    463  while (buflen) {
    464    rv = PR_Send(sd, buffer, buflen, 0, timeout);
    465    if (rv < 0) {
    466      /* PR_Send() has invoked PR_SetError(). */
    467      rv = -1;
    468      goto done;
    469    } else {
    470      count += rv;
    471      buffer = (const void*)((const char*)buffer + rv);
    472      buflen -= rv;
    473    }
    474  }
    475 
    476  /*
    477   * send file next
    478   */
    479  if (PR_Seek(sfd->fd, sfd->file_offset, PR_SEEK_SET) < 0) {
    480    rv = -1;
    481    goto done;
    482  }
    483  sendbytes = sfd->file_nbytes;
    484  if (sendbytes == 0) {
    485    /* send entire file */
    486    while ((rlen = PR_Read(sfd->fd, buf, _SENDFILE_BUFSIZE)) > 0) {
    487      while (rlen) {
    488        char* bufptr = buf;
    489 
    490        rv = PR_Send(sd, bufptr, rlen, 0, timeout);
    491        if (rv < 0) {
    492          /* PR_Send() has invoked PR_SetError(). */
    493          rv = -1;
    494          goto done;
    495        } else {
    496          count += rv;
    497          bufptr = ((char*)bufptr + rv);
    498          rlen -= rv;
    499        }
    500      }
    501    }
    502    if (rlen < 0) {
    503      /* PR_Read() has invoked PR_SetError(). */
    504      rv = -1;
    505      goto done;
    506    }
    507  } else {
    508    readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE);
    509    while (readbytes && ((rlen = PR_Read(sfd->fd, buf, readbytes)) > 0)) {
    510      while (rlen) {
    511        char* bufptr = buf;
    512 
    513        rv = PR_Send(sd, bufptr, rlen, 0, timeout);
    514        if (rv < 0) {
    515          /* PR_Send() has invoked PR_SetError(). */
    516          rv = -1;
    517          goto done;
    518        } else {
    519          count += rv;
    520          sendbytes -= rv;
    521          bufptr = ((char*)bufptr + rv);
    522          rlen -= rv;
    523        }
    524      }
    525      readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE);
    526    }
    527    if (rlen < 0) {
    528      /* PR_Read() has invoked PR_SetError(). */
    529      rv = -1;
    530      goto done;
    531    } else if (sendbytes != 0) {
    532      /*
    533       * there are fewer bytes in file to send than specified
    534       */
    535      PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    536      rv = -1;
    537      goto done;
    538    }
    539  }
    540 
    541  /*
    542   * send trailer last
    543   */
    544  buflen = sfd->tlen;
    545  buffer = sfd->trailer;
    546  while (buflen) {
    547    rv = PR_Send(sd, buffer, buflen, 0, timeout);
    548    if (rv < 0) {
    549      /* PR_Send() has invoked PR_SetError(). */
    550      rv = -1;
    551      goto done;
    552    } else {
    553      count += rv;
    554      buffer = (const void*)((const char*)buffer + rv);
    555      buflen -= rv;
    556    }
    557  }
    558  rv = count;
    559 
    560 done:
    561  if (buf) {
    562    PR_DELETE(buf);
    563  }
    564  if ((rv >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) {
    565    PR_Close(sd);
    566  }
    567  return rv;
    568 }
    569 
    570 #endif
    571 
    572 /* priometh.c */