emulate.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:16k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * Functions that emulate PR_AcceptRead and PR_TransmitFile for SSL sockets.
  3.  * Each Layered NSPR protocol (like SSL) must unfortunately contain its 
  4.  * own implementation of these functions.  This code was taken from NSPR.
  5.  *
  6.  * The contents of this file are subject to the Mozilla Public
  7.  * License Version 1.1 (the "License"); you may not use this file
  8.  * except in compliance with the License. You may obtain a copy of
  9.  * the License at http://www.mozilla.org/MPL/
  10.  * 
  11.  * Software distributed under the License is distributed on an "AS
  12.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  13.  * implied. See the License for the specific language governing
  14.  * rights and limitations under the License.
  15.  * 
  16.  * The Original Code is the Netscape security libraries.
  17.  * 
  18.  * The Initial Developer of the Original Code is Netscape
  19.  * Communications Corporation.  Portions created by Netscape are 
  20.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  21.  * Rights Reserved.
  22.  * 
  23.  * Contributor(s):
  24.  * 
  25.  * Alternatively, the contents of this file may be used under the
  26.  * terms of the GNU General Public License Version 2 or later (the
  27.  * "GPL"), in which case the provisions of the GPL are applicable 
  28.  * instead of those above.  If you wish to allow use of your 
  29.  * version of this file only under the terms of the GPL and not to
  30.  * allow others to use your version of this file under the MPL,
  31.  * indicate your decision by deleting the provisions above and
  32.  * replace them with the notice and other provisions required by
  33.  * the GPL.  If you do not delete the provisions above, a recipient
  34.  * may use your version of this file under either the MPL or the
  35.  * GPL.
  36.  *
  37.  * $Id: emulate.c,v 1.2 2000/05/18 01:32:53 nelsonb%netscape.com Exp $
  38.  */
  39. #include "nspr.h"
  40. #if defined( XP_UNIX )
  41. #include <fcntl.h>
  42. #endif
  43. #if defined(WIN32)
  44. #include <windef.h>
  45. #include <winbase.h>
  46. #endif
  47. #include <string.h>
  48. #define AMASK 7 /* mask for alignment of PRNetAddr */
  49. /*
  50.  * _PR_EmulateAcceptRead
  51.  *
  52.  *  Accept an incoming connection on sd, set *nd to point to the
  53.  *  newly accepted socket, read 'amount' bytes from the accepted
  54.  *  socket.
  55.  *
  56.  *  buf is a buffer of length = amount + (2 * sizeof(PRNetAddr)) + 32
  57.  *  *raddr points to the PRNetAddr of the accepted connection upon
  58.  *  return
  59.  *
  60.  *  return number of bytes read or -1 on error
  61.  *
  62.  */
  63. PRInt32 
  64. ssl_EmulateAcceptRead( PRFileDesc *   sd, 
  65. PRFileDesc **  nd,
  66. PRNetAddr **   raddr, 
  67. void *         buf, 
  68. PRInt32        amount, 
  69. PRIntervalTime timeout)
  70. {
  71.     PRFileDesc *   newsockfd;
  72.     PRInt32        rv;
  73.     PRNetAddr      remote;
  74.     if (!(newsockfd = PR_Accept(sd, &remote, PR_INTERVAL_NO_TIMEOUT))) {
  75. return -1;
  76.     }
  77.     rv = PR_Recv(newsockfd, buf, amount, 0, timeout);
  78.     if (rv >= 0) {
  79. ptrdiff_t pNetAddr = (((ptrdiff_t)buf) + amount + AMASK) & ~AMASK;
  80. *nd = newsockfd;
  81. *raddr = (PRNetAddr *)pNetAddr;
  82. memcpy((void *)pNetAddr, &remote, sizeof(PRNetAddr));
  83. return rv;
  84.     }
  85.     PR_Close(newsockfd);
  86.     return -1;
  87. }
  88. #if !defined( XP_UNIX ) && !defined( WIN32 )
  89. /*
  90.  * _PR_EmulateTransmitFile
  91.  *
  92.  *  Send file fd across socket sd. If headers is non-NULL, 'hlen'
  93.  *  bytes of headers is sent before sending the file.
  94.  *
  95.  *  PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  96.  *
  97.  *  return number of bytes sent or -1 on error
  98.  *
  99.  */
  100. #define _TRANSMITFILE_BUFSIZE (16 * 1024)
  101. PRInt32 
  102. ssl_EmulateTransmitFile(    PRFileDesc *        sd, 
  103.     PRFileDesc *        fd,
  104.     const void *        headers, 
  105.     PRInt32             hlen, 
  106.     PRTransmitFileFlags flags,
  107.     PRIntervalTime      timeout)
  108. {
  109.     char *  buf  = NULL;
  110.     PRInt32 count  = 0;
  111.     PRInt32 rlen;
  112.     PRInt32 rv;
  113.     buf = PR_MALLOC(_TRANSMITFILE_BUFSIZE);
  114.     if (buf == NULL) {
  115. PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  116. return -1;
  117.     }
  118.     /*
  119.      * send headers, first
  120.      */
  121.     while (hlen) {
  122. rv =  PR_Send(sd, headers, hlen, 0, timeout);
  123. if (rv < 0) {
  124.     /* PR_Send() has invoked PR_SetError(). */
  125.     rv = -1;
  126.     goto done;
  127. count += rv;
  128. headers = (const void*) ((const char*)headers + rv);
  129. hlen -= rv;
  130.     }
  131.     /*
  132.      * send file, next
  133.      */
  134.     while ((rlen = PR_Read(fd, buf, _TRANSMITFILE_BUFSIZE)) > 0) {
  135. while (rlen) {
  136.     char *bufptr = buf;
  137.     rv =  PR_Send(sd, bufptr, rlen,0,PR_INTERVAL_NO_TIMEOUT);
  138.     if (rv < 0) {
  139. /* PR_Send() has invoked PR_SetError(). */
  140. rv = -1;
  141. goto done;
  142.     } 
  143.     count += rv;
  144.     bufptr = ((char*)bufptr + rv);
  145.     rlen -= rv;
  146. }
  147.     }
  148.     if (rlen == 0) {
  149. /*
  150.  * end-of-file
  151.  */
  152. if (flags & PR_TRANSMITFILE_CLOSE_SOCKET)
  153.     PR_Close(sd);
  154. rv = count;
  155.     } else {
  156. PR_ASSERT(rlen < 0);
  157. /* PR_Read() has invoked PR_SetError(). */
  158. rv = -1;
  159.     }
  160. done:
  161.     if (buf)
  162. PR_DELETE(buf);
  163.     return rv;
  164. }
  165. #else
  166. #define TRANSMITFILE_MMAP_CHUNK (256 * 1024)
  167. /*
  168.  * _PR_UnixTransmitFile
  169.  *
  170.  *  Send file fd across socket sd. If headers is non-NULL, 'hlen'
  171.  *  bytes of headers is sent before sending the file.
  172.  *
  173.  *  PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  174.  *
  175.  *  return number of bytes sent or -1 on error
  176.  *
  177.  */
  178. PRInt32 
  179. ssl_EmulateTransmitFile(    PRFileDesc *        sd, 
  180.     PRFileDesc *        fd,
  181.     const void *        headers, 
  182.     PRInt32             hlen, 
  183.     PRTransmitFileFlags flags,
  184.     PRIntervalTime      timeout)
  185. {
  186.     void *            addr;
  187.     PRFileMap *       mapHandle = NULL;
  188.     PRInt32           count     = 0;
  189.     PRInt32           index     = 0;
  190.     PRInt32           len = 0;
  191.     PRInt32           rv;
  192.     struct PRFileInfo info;
  193.     struct PRIOVec    iov[2];
  194.     /* Get file size */
  195.     if (PR_SUCCESS != PR_GetOpenFileInfo(fd, &info)) {
  196. count = -1;
  197. goto done;
  198.     }
  199.     if (hlen) {
  200. iov[index].iov_base = (char *) headers;
  201. iov[index].iov_len  = hlen;
  202. index++;
  203.     }
  204.     if (info.size > 0) {
  205. mapHandle = PR_CreateFileMap(fd, info.size, PR_PROT_READONLY);
  206. if (mapHandle == NULL) {
  207.     count = -1;
  208.     goto done;
  209. }
  210. /*
  211.  * If the file is large, mmap and send the file in chunks so as
  212.  * to not consume too much virtual address space
  213.  */
  214. len = PR_MIN(info.size , TRANSMITFILE_MMAP_CHUNK );
  215. /*
  216.  * Map in (part of) file. Take care of zero-length files.
  217.  */
  218. if (len) {
  219.     addr = PR_MemMap(mapHandle, 0, len);
  220.     if (addr == NULL) {
  221. count = -1;
  222. goto done;
  223.     }
  224. }
  225. iov[index].iov_base = (char*)addr;
  226. iov[index].iov_len = len;
  227. index++;
  228.     }
  229.     if (!index)
  230.      goto done;
  231.     rv = PR_Writev(sd, iov, index, timeout);
  232.     if (len) {
  233. PR_MemUnmap(addr, len);
  234.     }
  235.     if (rv >= 0) {
  236. PR_ASSERT(rv == hlen + len);
  237. info.size -= len;
  238. count     += rv;
  239.     } else {
  240. count = -1;
  241. goto done;
  242.     }
  243.     /*
  244.      * send remaining bytes of the file, if any
  245.      */
  246.     len = PR_MIN(info.size , TRANSMITFILE_MMAP_CHUNK );
  247.     while (len > 0) {
  248. /*
  249.  * Map in (part of) file
  250.  */
  251. PR_ASSERT((count - hlen) % TRANSMITFILE_MMAP_CHUNK == 0);
  252. addr = PR_MemMap(mapHandle, count - hlen, len);
  253. if (addr == NULL) {
  254.     count = -1;
  255.     goto done;
  256. }
  257. rv =  PR_Send(sd, addr, len, 0, timeout);
  258. PR_MemUnmap(addr, len);
  259. if (rv >= 0) {
  260.     PR_ASSERT(rv == len);
  261.     info.size -= rv;
  262.     count     += rv;
  263.     len = PR_MIN(info.size , TRANSMITFILE_MMAP_CHUNK );
  264. } else {
  265.     count = -1;
  266.     goto done;
  267. }
  268.     }
  269. done:
  270.     if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET))
  271. PR_Close(sd);
  272.     if (mapHandle != NULL)
  273.      PR_CloseFileMap(mapHandle);
  274.     return count;
  275. }
  276. #endif  /* XP_UNIX */
  277. #if !defined( XP_UNIX ) && !defined( WIN32 )
  278. /*
  279.  * _PR_EmulateSendFile
  280.  *
  281.  *  Send file sfd->fd across socket sd. The header and trailer buffers
  282.  *  specified in the 'sfd' argument are sent before and after the file,
  283.  *  respectively.
  284.  *
  285.  *  PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  286.  *
  287.  *  return number of bytes sent or -1 on error
  288.  *
  289.  */
  290. PRInt32 
  291. ssl_EmulateSendFile(PRFileDesc *sd, PRSendFileData *sfd,
  292.                     PRTransmitFileFlags flags, PRIntervalTime timeout)
  293. {
  294.     char *       buf = NULL;
  295.     const void * buffer;
  296.     PRInt32      rv;
  297.     PRInt32      count = 0;
  298.     PRInt32      rlen;
  299.     PRInt32      buflen;
  300.     PRInt32      sendbytes;
  301.     PRInt32      readbytes;
  302. #define _SENDFILE_BUFSIZE   (16 * 1024)
  303.     buf = (char*)PR_MALLOC(_SENDFILE_BUFSIZE);
  304.     if (buf == NULL) {
  305.         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  306.         return -1;
  307.     }
  308.     /*
  309.      * send header, first
  310.      */
  311.     buflen = sfd->hlen;
  312.     buffer = sfd->header;
  313.     while (buflen) {
  314.         rv =  PR_Send(sd, buffer, buflen, 0, timeout);
  315.         if (rv < 0) {
  316.             /* PR_Send() has invoked PR_SetError(). */
  317.             rv = -1;
  318.             goto done;
  319.         } else {
  320.             count += rv;
  321.             buffer = (const void*) ((const char*)buffer + rv);
  322.             buflen -= rv;
  323.         }
  324.     }
  325.     /*
  326.      * send file, next
  327.      */
  328.     if (PR_Seek(sfd->fd, sfd->file_offset, PR_SEEK_SET) < 0) {
  329.         rv = -1;
  330.         goto done;
  331.     }
  332.     sendbytes = sfd->file_nbytes;
  333.     if (sendbytes == 0) {
  334.         /* send entire file */
  335.         while ((rlen = PR_Read(sfd->fd, buf, _SENDFILE_BUFSIZE)) > 0) {
  336.             while (rlen) {
  337.                 char *bufptr = buf;
  338.                 rv =  PR_Send(sd, bufptr, rlen, 0, timeout);
  339.                 if (rv < 0) {
  340.                     /* PR_Send() has invoked PR_SetError(). */
  341.                     rv = -1;
  342.                     goto done;
  343.                 } else {
  344.                     count += rv;
  345.                     bufptr = ((char*)bufptr + rv);
  346.                     rlen -= rv;
  347.                 }
  348.             }
  349.         }
  350.         if (rlen < 0) {
  351.             /* PR_Read() has invoked PR_SetError(). */
  352.             rv = -1;
  353.             goto done;
  354.         }
  355.     } else {
  356.         readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE);
  357.         while (readbytes && ((rlen = PR_Read(sfd->fd, buf, readbytes)) > 0)) {
  358.             while (rlen) {
  359.                 char *bufptr = buf;
  360.                 rv =  PR_Send(sd, bufptr, rlen, 0, timeout);
  361.                 if (rv < 0) {
  362.                     /* PR_Send() has invoked PR_SetError(). */
  363.                     rv = -1;
  364.                     goto done;
  365.                 } else {
  366.                     count += rv;
  367.                     sendbytes -= rv;
  368.                     bufptr = ((char*)bufptr + rv);
  369.                     rlen -= rv;
  370.                 }
  371.             }
  372.     readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE);
  373.         }
  374.         if (rlen < 0) {
  375.             /* PR_Read() has invoked PR_SetError(). */
  376.             rv = -1;
  377.             goto done;
  378.         } else if (sendbytes != 0) {
  379.             /*
  380.              * there are fewer bytes in file to send than specified
  381.              */
  382.     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  383.             rv = -1;
  384.             goto done;
  385.         }
  386.     }
  387.     /*
  388.      * send trailer, last
  389.      */
  390.     buflen = sfd->tlen;
  391.     buffer = sfd->trailer;
  392.     while (buflen) {
  393.         rv =  PR_Send(sd, buffer, buflen, 0, timeout);
  394.         if (rv < 0) {
  395.             /* PR_Send() has invoked PR_SetError(). */
  396.             rv = -1;
  397.             goto done;
  398.         } else {
  399.             count += rv;
  400.             buffer = (const void*) ((const char*)buffer + rv);
  401.             buflen -= rv;
  402.         }
  403.     }
  404.     rv = count;
  405. done:
  406.     if (buf)
  407.         PR_DELETE(buf);
  408.     if ((rv >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET))
  409. PR_Close(sd);
  410.     return rv;
  411. }
  412. #else /* UNIX and NT handled below */
  413. /*
  414.  * _PR_UnixSendFile
  415.  *
  416.  *    Send file sfd->fd across socket sd. If header/trailer are specified
  417.  *    they are sent before and after the file, respectively.
  418.  *
  419.  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  420.  *
  421.  *    return number of bytes sent or -1 on error
  422.  *
  423.  */
  424. #define SENDFILE_MMAP_CHUNK    (256 * 1024)
  425. PRInt32 
  426. ssl_EmulateSendFile(PRFileDesc *sd, PRSendFileData *sfd,
  427.                     PRTransmitFileFlags flags, PRIntervalTime timeout)
  428. {
  429.     void *            addr;
  430.     PRFileMap *       mapHandle   = NULL;
  431.     PRInt32           count  = 0;
  432.     PRInt32           file_bytes;
  433.     PRInt32           index  = 0;
  434.     PRInt32           len;
  435.     PRInt32           rv;
  436.     PRUint32          addr_offset;
  437.     PRUint32          file_mmap_offset;
  438.     PRUint32          mmap_len;
  439.     PRUint32          pagesize;
  440.     struct PRFileInfo info;
  441.     struct PRIOVec    iov[3];
  442.     /* Get file size */
  443.     if (PR_SUCCESS != PR_GetOpenFileInfo(sfd->fd, &info)) {
  444. count = -1;
  445. goto done;
  446.     }
  447.     if (sfd->file_nbytes && 
  448. (info.size < (sfd->file_offset + sfd->file_nbytes))) {
  449.         /*
  450.          * there are fewer bytes in file to send than specified
  451.          */
  452. PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  453.         count = -1;
  454.         goto done;
  455.     }
  456.     if (sfd->file_nbytes)
  457.         file_bytes = sfd->file_nbytes;
  458.     else
  459.         file_bytes = info.size - sfd->file_offset;
  460. #if defined(WIN32)
  461.     {
  462.         SYSTEM_INFO sysinfo;
  463.         GetSystemInfo(&sysinfo);
  464.         pagesize = sysinfo.dwAllocationGranularity;
  465.     }
  466. #else
  467.     pagesize = PR_GetPageSize();
  468. #endif
  469.     /*
  470.      * If the file is large, mmap and send the file in chunks so as
  471.      * to not consume too much virtual address space
  472.      */
  473.     if (!sfd->file_offset || !(sfd->file_offset & (pagesize - 1))) {
  474.         /*
  475.          * case 1: page-aligned file offset
  476.          */
  477.         mmap_len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
  478.         len      = mmap_len;
  479.         file_mmap_offset = sfd->file_offset;
  480.         addr_offset = 0;
  481.     } else {
  482.         /*
  483.          * case 2: non page-aligned file offset
  484.          */
  485.         /* find previous page boundary */
  486.         file_mmap_offset = (sfd->file_offset & ~(pagesize - 1));
  487.         /* number of initial bytes to skip in mmap'd segment */
  488.         addr_offset = sfd->file_offset - file_mmap_offset;
  489.         PR_ASSERT(addr_offset > 0);
  490.         mmap_len = PR_MIN(file_bytes + addr_offset, SENDFILE_MMAP_CHUNK);
  491.         len      = mmap_len - addr_offset;
  492.     }
  493.     /*
  494.      * Map in (part of) file. Take care of zero-length files.
  495.      */
  496.     if (len > 0) {
  497. mapHandle = PR_CreateFileMap(sfd->fd, info.size, PR_PROT_READONLY);
  498. if (!mapHandle) {
  499.     count = -1;
  500.     goto done;
  501. }
  502. addr = PR_MemMap(mapHandle, file_mmap_offset, mmap_len);
  503.         if (!addr) {
  504.             count = -1;
  505.             goto done;
  506.         }
  507.     }
  508.     /*
  509.      * send headers, first, followed by the file
  510.      */
  511.     if (sfd->hlen) {
  512.         iov[index].iov_base = (char *) sfd->header;
  513.         iov[index].iov_len  = sfd->hlen;
  514.         index++;
  515.     }
  516.     if (len) {
  517.         iov[index].iov_base = (char*)addr + addr_offset;
  518.         iov[index].iov_len  = len;
  519.         index++;
  520.     }
  521.     if ((file_bytes == len) && (sfd->tlen)) {
  522.         /*
  523.          * all file data is mapped in; send the trailer too
  524.          */
  525.         iov[index].iov_base = (char *) sfd->trailer;
  526.         iov[index].iov_len  = sfd->tlen;
  527.         index++;
  528.     }
  529.     rv = PR_Writev(sd, iov, index, timeout);
  530.     if (len)
  531.         PR_MemUnmap(addr, mmap_len);
  532.     if (rv < 0) {
  533.         count = -1;
  534.         goto done;
  535.     }
  536.     PR_ASSERT(rv == sfd->hlen + len + ((len == file_bytes) ? sfd->tlen : 0));
  537.     file_bytes -= len;
  538.     count      += rv;
  539.     if (!file_bytes)    /* header, file and trailer are sent */
  540. goto done;
  541.     /*
  542.      * send remaining bytes of the file, if any
  543.      */
  544.     len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
  545.     while (len > 0) {
  546. /*
  547.  * Map in (part of) file
  548.  */
  549. file_mmap_offset = sfd->file_offset + count - sfd->hlen;
  550. PR_ASSERT((file_mmap_offset % pagesize) == 0);
  551. addr = PR_MemMap(mapHandle, file_mmap_offset, len);
  552.         if (!addr) {
  553.             count = -1;
  554.             goto done;
  555.         }
  556. rv = PR_Send(sd, addr, len, 0, timeout);
  557. PR_MemUnmap(addr, len);
  558. if (rv < 0) {
  559.     count = -1;
  560.     goto done;
  561. }
  562. PR_ASSERT(rv == len);
  563. file_bytes -= rv;
  564. count      += rv;
  565. len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
  566.     }
  567.     PR_ASSERT(0 == file_bytes);
  568.     if (sfd->tlen) {
  569.         rv =  PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
  570.         if (rv >= 0) {
  571.             PR_ASSERT(rv == sfd->tlen);
  572.             count += rv;
  573.         } else
  574.             count = -1;
  575.     }
  576. done:
  577.     if (mapHandle)
  578.      PR_CloseFileMap(mapHandle);
  579.     if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET))
  580. PR_Close(sd);
  581.     return count;
  582. }
  583. #endif /* UNIX and NT */