Back to index

lightning-sunbird  0.9+nobinonly
priometh.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Netscape Portable Runtime (NSPR).
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 #include "primpl.h"
00039 
00040 #include <string.h>
00041 
00042 /*****************************************************************************/
00043 /************************** Invalid I/O method object ************************/
00044 /*****************************************************************************/
00045 PRIOMethods _pr_faulty_methods = {
00046     (PRDescType)0,
00047     (PRCloseFN)_PR_InvalidStatus,
00048     (PRReadFN)_PR_InvalidInt,
00049     (PRWriteFN)_PR_InvalidInt,
00050     (PRAvailableFN)_PR_InvalidInt,
00051     (PRAvailable64FN)_PR_InvalidInt64,
00052     (PRFsyncFN)_PR_InvalidStatus,
00053     (PRSeekFN)_PR_InvalidInt,
00054     (PRSeek64FN)_PR_InvalidInt64,
00055     (PRFileInfoFN)_PR_InvalidStatus,
00056     (PRFileInfo64FN)_PR_InvalidStatus,
00057     (PRWritevFN)_PR_InvalidInt,        
00058     (PRConnectFN)_PR_InvalidStatus,        
00059     (PRAcceptFN)_PR_InvalidDesc,        
00060     (PRBindFN)_PR_InvalidStatus,        
00061     (PRListenFN)_PR_InvalidStatus,        
00062     (PRShutdownFN)_PR_InvalidStatus,    
00063     (PRRecvFN)_PR_InvalidInt,        
00064     (PRSendFN)_PR_InvalidInt,        
00065     (PRRecvfromFN)_PR_InvalidInt,    
00066     (PRSendtoFN)_PR_InvalidInt,        
00067     (PRPollFN)_PR_InvalidInt16,
00068     (PRAcceptreadFN)_PR_InvalidInt,   
00069     (PRTransmitfileFN)_PR_InvalidInt, 
00070     (PRGetsocknameFN)_PR_InvalidStatus,    
00071     (PRGetpeernameFN)_PR_InvalidStatus,    
00072     (PRReservedFN)_PR_InvalidInt,    
00073     (PRReservedFN)_PR_InvalidInt,    
00074     (PRGetsocketoptionFN)_PR_InvalidStatus,
00075     (PRSetsocketoptionFN)_PR_InvalidStatus,
00076     (PRSendfileFN)_PR_InvalidInt, 
00077     (PRConnectcontinueFN)_PR_InvalidStatus,
00078     (PRReservedFN)_PR_InvalidInt,
00079     (PRReservedFN)_PR_InvalidInt,
00080     (PRReservedFN)_PR_InvalidInt,
00081     (PRReservedFN)_PR_InvalidInt
00082 };
00083 
00084 PRIntn _PR_InvalidInt(void)
00085 {
00086     PR_ASSERT(!"I/O method is invalid");
00087     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
00088     return -1;
00089 }  /* _PR_InvalidInt */
00090 
00091 PRInt16 _PR_InvalidInt16(void)
00092 {
00093     PR_ASSERT(!"I/O method is invalid");
00094     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
00095     return -1;
00096 }  /* _PR_InvalidInt */
00097 
00098 PRInt64 _PR_InvalidInt64(void)
00099 {
00100     PRInt64 rv;
00101     LL_I2L(rv, -1);
00102     PR_ASSERT(!"I/O method is invalid");
00103     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
00104     return rv;
00105 }  /* _PR_InvalidInt */
00106 
00107 /*
00108  * An invalid method that returns PRStatus
00109  */
00110 
00111 PRStatus _PR_InvalidStatus(void)
00112 {
00113     PR_ASSERT(!"I/O method is invalid");
00114     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
00115     return PR_FAILURE;
00116 }  /* _PR_InvalidDesc */
00117 
00118 /*
00119  * An invalid method that returns a pointer
00120  */
00121 
00122 PRFileDesc *_PR_InvalidDesc(void)
00123 {
00124     PR_ASSERT(!"I/O method is invalid");
00125     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
00126     return NULL;
00127 }  /* _PR_InvalidDesc */
00128 
00129 PR_IMPLEMENT(PRDescType) PR_GetDescType(PRFileDesc *file)
00130 {
00131     return file->methods->file_type;
00132 }
00133 
00134 PR_IMPLEMENT(PRStatus) PR_Close(PRFileDesc *fd)
00135 {
00136     return (fd->methods->close)(fd);
00137 }
00138 
00139 PR_IMPLEMENT(PRInt32) PR_Read(PRFileDesc *fd, void *buf, PRInt32 amount)
00140 {
00141        return((fd->methods->read)(fd,buf,amount));
00142 }
00143 
00144 PR_IMPLEMENT(PRInt32) PR_Write(PRFileDesc *fd, const void *buf, PRInt32 amount)
00145 {
00146        return((fd->methods->write)(fd,buf,amount));
00147 }
00148 
00149 PR_IMPLEMENT(PRInt32) PR_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence)
00150 {
00151        return((fd->methods->seek)(fd, offset, whence));
00152 }
00153 
00154 PR_IMPLEMENT(PRInt64) PR_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence)
00155 {
00156        return((fd->methods->seek64)(fd, offset, whence));
00157 }
00158 
00159 PR_IMPLEMENT(PRInt32) PR_Available(PRFileDesc *fd)
00160 {
00161        return((fd->methods->available)(fd));
00162 }
00163 
00164 PR_IMPLEMENT(PRInt64) PR_Available64(PRFileDesc *fd)
00165 {
00166        return((fd->methods->available64)(fd));
00167 }
00168 
00169 PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo(PRFileDesc *fd, PRFileInfo *info)
00170 {
00171        return((fd->methods->fileInfo)(fd, info));
00172 }
00173 
00174 PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo64(PRFileDesc *fd, PRFileInfo64 *info)
00175 {
00176        return((fd->methods->fileInfo64)(fd, info));
00177 }
00178 
00179 PR_IMPLEMENT(PRStatus) PR_Sync(PRFileDesc *fd)
00180 {
00181        return((fd->methods->fsync)(fd));
00182 }
00183 
00184 PR_IMPLEMENT(PRStatus) PR_Connect(
00185     PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
00186 {
00187        return((fd->methods->connect)(fd,addr,timeout));
00188 }
00189 
00190 PR_IMPLEMENT(PRStatus) PR_ConnectContinue(
00191     PRFileDesc *fd, PRInt16 out_flags)
00192 {
00193        return((fd->methods->connectcontinue)(fd,out_flags));
00194 }
00195 
00196 PR_IMPLEMENT(PRFileDesc*) PR_Accept(PRFileDesc *fd, PRNetAddr *addr,
00197 PRIntervalTime timeout)
00198 {
00199        return((fd->methods->accept)(fd,addr,timeout));
00200 }
00201 
00202 PR_IMPLEMENT(PRStatus) PR_Bind(PRFileDesc *fd, const PRNetAddr *addr)
00203 {
00204        return((fd->methods->bind)(fd,addr));
00205 }
00206 
00207 PR_IMPLEMENT(PRStatus) PR_Shutdown(PRFileDesc *fd, PRShutdownHow how)
00208 {
00209        return((fd->methods->shutdown)(fd,how));
00210 }
00211 
00212 PR_IMPLEMENT(PRStatus) PR_Listen(PRFileDesc *fd, PRIntn backlog)
00213 {
00214        return((fd->methods->listen)(fd,backlog));
00215 }
00216 
00217 PR_IMPLEMENT(PRInt32) PR_Recv(PRFileDesc *fd, void *buf, PRInt32 amount,
00218 PRIntn flags, PRIntervalTime timeout)
00219 {
00220        return((fd->methods->recv)(fd,buf,amount,flags,timeout));
00221 }
00222 
00223 PR_IMPLEMENT(PRInt32) PR_Send(PRFileDesc *fd, const void *buf, PRInt32 amount,
00224 PRIntn flags, PRIntervalTime timeout)
00225 {
00226        return((fd->methods->send)(fd,buf,amount,flags,timeout));
00227 }
00228 
00229 PR_IMPLEMENT(PRInt32) PR_Writev(PRFileDesc *fd, const PRIOVec *iov,
00230 PRInt32 iov_size, PRIntervalTime timeout)
00231 {
00232     if (iov_size > PR_MAX_IOVECTOR_SIZE)
00233     {
00234         PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
00235         return -1;
00236     }
00237        return((fd->methods->writev)(fd,iov,iov_size,timeout));
00238 }
00239 
00240 PR_IMPLEMENT(PRInt32) PR_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
00241 PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
00242 {
00243        return((fd->methods->recvfrom)(fd,buf,amount,flags,addr,timeout));
00244 }
00245 
00246 PR_IMPLEMENT(PRInt32) PR_SendTo(
00247     PRFileDesc *fd, const void *buf, PRInt32 amount,
00248     PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
00249 {
00250        return((fd->methods->sendto)(fd,buf,amount,flags,addr,timeout));
00251 }
00252 
00253 PR_IMPLEMENT(PRInt32) PR_TransmitFile(
00254     PRFileDesc *sd, PRFileDesc *fd, const void *hdr, PRInt32 hlen,
00255     PRTransmitFileFlags flags, PRIntervalTime timeout)
00256 {
00257        return((sd->methods->transmitfile)(sd,fd,hdr,hlen,flags,timeout));
00258 }
00259 
00260 PR_IMPLEMENT(PRInt32) PR_AcceptRead(
00261     PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
00262     void *buf, PRInt32 amount, PRIntervalTime timeout)
00263 {
00264        return((sd->methods->acceptread)(sd, nd, raddr, buf, amount,timeout));
00265 }
00266 
00267 PR_IMPLEMENT(PRStatus) PR_GetSockName(PRFileDesc *fd, PRNetAddr *addr)
00268 {
00269        return((fd->methods->getsockname)(fd,addr));
00270 }
00271 
00272 PR_IMPLEMENT(PRStatus) PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
00273 {
00274        return((fd->methods->getpeername)(fd,addr));
00275 }
00276 
00277 PR_IMPLEMENT(PRStatus) PR_GetSocketOption(
00278     PRFileDesc *fd, PRSocketOptionData *data)
00279 {
00280        return((fd->methods->getsocketoption)(fd, data));
00281 }
00282 
00283 PR_IMPLEMENT(PRStatus) PR_SetSocketOption(
00284     PRFileDesc *fd, const PRSocketOptionData *data)
00285 {
00286        return((fd->methods->setsocketoption)(fd, data));
00287 }
00288 
00289 PR_IMPLEMENT(PRInt32) PR_SendFile(
00290        PRFileDesc *sd, PRSendFileData *sfd,
00291        PRTransmitFileFlags flags, PRIntervalTime timeout)
00292 {
00293        return((sd->methods->sendfile)(sd,sfd,flags,timeout));
00294 }
00295 
00296 PR_IMPLEMENT(PRInt32) PR_EmulateAcceptRead(
00297     PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
00298     void *buf, PRInt32 amount, PRIntervalTime timeout)
00299 {
00300     PRInt32 rv = -1;
00301     PRNetAddr remote;
00302     PRFileDesc *accepted = NULL;
00303 
00304     /*
00305     ** The timeout does not apply to the accept portion of the
00306     ** operation - it waits indefinitely.
00307     */
00308     accepted = PR_Accept(sd, &remote, PR_INTERVAL_NO_TIMEOUT);
00309     if (NULL == accepted) return rv;
00310 
00311     rv = PR_Recv(accepted, buf, amount, 0, timeout);
00312     if (rv >= 0)
00313     {
00314         /* copy the new info out where caller can see it */
00315 #define AMASK ((PRPtrdiff)7)  /* mask for alignment of PRNetAddr */
00316         PRPtrdiff aligned = (PRPtrdiff)buf + amount + AMASK;
00317         *raddr = (PRNetAddr*)(aligned & ~AMASK);
00318         memcpy(*raddr, &remote, PR_NETADDR_SIZE(&remote));
00319         *nd = accepted;
00320         return rv;
00321     }
00322 
00323     PR_Close(accepted);
00324     return rv;
00325 }
00326 
00327 /*
00328  * PR_EmulateSendFile
00329  *
00330  *    Send file sfd->fd across socket sd. If header/trailer are specified
00331  *    they are sent before and after the file, respectively.
00332  *
00333  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
00334  *    
00335  *    return number of bytes sent or -1 on error
00336  *
00337  */
00338 
00339 #if defined(XP_UNIX) || defined(WIN32)
00340 
00341 /*
00342  * An implementation based on memory-mapped files
00343  */
00344 
00345 #define SENDFILE_MMAP_CHUNK (256 * 1024)
00346 
00347 PR_IMPLEMENT(PRInt32) PR_EmulateSendFile(
00348     PRFileDesc *sd, PRSendFileData *sfd,
00349     PRTransmitFileFlags flags, PRIntervalTime timeout)
00350 {
00351     PRInt32 rv, count = 0;
00352     PRInt32 len, file_bytes, index = 0;
00353     PRFileInfo info;
00354     PRIOVec iov[3];
00355     PRFileMap *mapHandle = NULL;
00356     void *addr = (void*)0; /* initialized to some arbitrary value. Keeps compiler warnings down. */
00357     PRUint32 file_mmap_offset, alignment;
00358     PRInt64 zero64;
00359     PROffset64 file_mmap_offset64;
00360     PRUint32 addr_offset, mmap_len;
00361 
00362     /* Get file size */
00363     if (PR_SUCCESS != PR_GetOpenFileInfo(sfd->fd, &info)) {
00364         count = -1;
00365         goto done;
00366     }
00367     if (sfd->file_nbytes &&
00368             (info.size < (sfd->file_offset + sfd->file_nbytes))) {
00369         /*
00370          * there are fewer bytes in file to send than specified
00371          */
00372         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00373         count = -1;
00374         goto done;
00375     }
00376     if (sfd->file_nbytes)
00377         file_bytes = sfd->file_nbytes;
00378     else
00379         file_bytes = info.size - sfd->file_offset;
00380 
00381     alignment = PR_GetMemMapAlignment();
00382 
00383     /* number of initial bytes to skip in mmap'd segment */
00384     addr_offset = sfd->file_offset % alignment;
00385 
00386     /* find previous mmap alignment boundary */
00387     file_mmap_offset = sfd->file_offset - addr_offset;
00388 
00389     /*
00390      * If the file is large, mmap and send the file in chunks so as
00391      * to not consume too much virtual address space
00392      */
00393     mmap_len = PR_MIN(file_bytes + addr_offset, SENDFILE_MMAP_CHUNK);
00394     len = mmap_len - addr_offset;
00395 
00396     /*
00397      * Map in (part of) file. Take care of zero-length files.
00398      */
00399     if (len) {
00400         LL_I2L(zero64, 0);
00401         mapHandle = PR_CreateFileMap(sfd->fd, zero64, PR_PROT_READONLY);
00402         if (!mapHandle) {
00403             count = -1;
00404             goto done;
00405         }
00406         LL_I2L(file_mmap_offset64, file_mmap_offset);
00407         addr = PR_MemMap(mapHandle, file_mmap_offset64, mmap_len);
00408         if (!addr) {
00409             count = -1;
00410             goto done;
00411         }
00412     }
00413     /*
00414      * send headers first, followed by the file
00415      */
00416     if (sfd->hlen) {
00417         iov[index].iov_base = (char *) sfd->header;
00418         iov[index].iov_len = sfd->hlen;
00419         index++;
00420     }
00421     if (len) {
00422         iov[index].iov_base = (char*)addr + addr_offset;
00423         iov[index].iov_len = len;
00424         index++;
00425     }
00426     if ((file_bytes == len) && (sfd->tlen)) {
00427         /*
00428          * all file data is mapped in; send the trailer too
00429          */
00430         iov[index].iov_base = (char *) sfd->trailer;
00431         iov[index].iov_len = sfd->tlen;
00432         index++;
00433     }
00434     rv = PR_Writev(sd, iov, index, timeout);
00435     if (len)
00436         PR_MemUnmap(addr, mmap_len);
00437     if (rv < 0) {
00438         count = -1;
00439         goto done;
00440     }
00441 
00442     PR_ASSERT(rv == sfd->hlen + len + ((len == file_bytes) ? sfd->tlen : 0));
00443 
00444     file_bytes -= len;
00445     count += rv;
00446     if (!file_bytes)    /* header, file and trailer are sent */
00447         goto done;
00448 
00449     /*
00450      * send remaining bytes of the file, if any
00451      */
00452     len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
00453     while (len > 0) {
00454         /*
00455          * Map in (part of) file
00456          */
00457         file_mmap_offset = sfd->file_offset + count - sfd->hlen;
00458         PR_ASSERT((file_mmap_offset % alignment) == 0);
00459 
00460         LL_I2L(file_mmap_offset64, file_mmap_offset);
00461         addr = PR_MemMap(mapHandle, file_mmap_offset64, len);
00462         if (!addr) {
00463             count = -1;
00464             goto done;
00465         }
00466         rv = PR_Send(sd, addr, len, 0, timeout);
00467         PR_MemUnmap(addr, len);
00468         if (rv < 0) {
00469             count = -1;
00470             goto done;
00471         }
00472 
00473         PR_ASSERT(rv == len);
00474         file_bytes -= rv;
00475         count += rv;
00476         len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
00477     }
00478     PR_ASSERT(0 == file_bytes);
00479     if (sfd->tlen) {
00480         rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
00481         if (rv >= 0) {
00482             PR_ASSERT(rv == sfd->tlen);
00483             count += rv;
00484         } else
00485             count = -1;
00486     }
00487 done:
00488     if (mapHandle)
00489         PR_CloseFileMap(mapHandle);
00490     if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET))
00491         PR_Close(sd);
00492     return count;
00493 }
00494 
00495 #else
00496 
00497 PR_IMPLEMENT(PRInt32) PR_EmulateSendFile(
00498     PRFileDesc *sd, PRSendFileData *sfd,
00499     PRTransmitFileFlags flags, PRIntervalTime timeout)
00500 {
00501     PRInt32 rv, count = 0;
00502     PRInt32 rlen;
00503     const void * buffer;
00504     PRInt32 buflen;
00505     PRInt32 sendbytes, readbytes;
00506     char *buf;
00507 
00508 #define _SENDFILE_BUFSIZE   (16 * 1024)
00509 
00510     buf = (char*)PR_MALLOC(_SENDFILE_BUFSIZE);
00511     if (buf == NULL) {
00512         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00513         return -1;
00514     }
00515 
00516     /*
00517      * send header first
00518      */
00519     buflen = sfd->hlen;
00520     buffer = sfd->header;
00521     while (buflen) {
00522         rv = PR_Send(sd, buffer, buflen, 0, timeout);
00523         if (rv < 0) {
00524             /* PR_Send() has invoked PR_SetError(). */
00525             rv = -1;
00526             goto done;
00527         } else {
00528             count += rv;
00529             buffer = (const void*) ((const char*)buffer + rv);
00530             buflen -= rv;
00531         }
00532     }
00533 
00534     /*
00535      * send file next
00536      */
00537     if (PR_Seek(sfd->fd, sfd->file_offset, PR_SEEK_SET) < 0) {
00538         rv = -1;
00539         goto done;
00540     }
00541     sendbytes = sfd->file_nbytes;
00542     if (sendbytes == 0) {
00543         /* send entire file */
00544         while ((rlen = PR_Read(sfd->fd, buf, _SENDFILE_BUFSIZE)) > 0) {
00545             while (rlen) {
00546                 char *bufptr = buf;
00547 
00548                 rv =  PR_Send(sd, bufptr, rlen, 0, timeout);
00549                 if (rv < 0) {
00550                     /* PR_Send() has invoked PR_SetError(). */
00551                     rv = -1;
00552                     goto done;
00553                 } else {
00554                     count += rv;
00555                     bufptr = ((char*)bufptr + rv);
00556                     rlen -= rv;
00557                 }
00558             }
00559         }
00560         if (rlen < 0) {
00561             /* PR_Read() has invoked PR_SetError(). */
00562             rv = -1;
00563             goto done;
00564         }
00565     } else {
00566         readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE);
00567         while (readbytes && ((rlen = PR_Read(sfd->fd, buf, readbytes)) > 0)) {
00568             while (rlen) {
00569                 char *bufptr = buf;
00570 
00571                 rv =  PR_Send(sd, bufptr, rlen, 0, timeout);
00572                 if (rv < 0) {
00573                     /* PR_Send() has invoked PR_SetError(). */
00574                     rv = -1;
00575                     goto done;
00576                 } else {
00577                     count += rv;
00578                     sendbytes -= rv;
00579                     bufptr = ((char*)bufptr + rv);
00580                     rlen -= rv;
00581                 }
00582             }
00583             readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE);
00584         }
00585         if (rlen < 0) {
00586             /* PR_Read() has invoked PR_SetError(). */
00587             rv = -1;
00588             goto done;
00589         } else if (sendbytes != 0) {
00590             /*
00591              * there are fewer bytes in file to send than specified
00592              */
00593             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00594             rv = -1;
00595             goto done;
00596         }
00597     }
00598 
00599     /*
00600      * send trailer last
00601      */
00602     buflen = sfd->tlen;
00603     buffer = sfd->trailer;
00604     while (buflen) {
00605         rv =  PR_Send(sd, buffer, buflen, 0, timeout);
00606         if (rv < 0) {
00607             /* PR_Send() has invoked PR_SetError(). */
00608             rv = -1;
00609             goto done;
00610         } else {
00611             count += rv;
00612             buffer = (const void*) ((const char*)buffer + rv);
00613             buflen -= rv;
00614         }
00615     }
00616     rv = count;
00617 
00618 done:
00619     if (buf)
00620         PR_DELETE(buf);
00621     if ((rv >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET))
00622         PR_Close(sd);
00623     return rv;
00624 }
00625 
00626 #endif
00627 
00628 /* priometh.c */