nsprpub/pr/src/io/priometh.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial