1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/io/priometh.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,596 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 + 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 +#include "primpl.h" 1.10 + 1.11 +#include <string.h> 1.12 + 1.13 +/*****************************************************************************/ 1.14 +/************************** Invalid I/O method object ************************/ 1.15 +/*****************************************************************************/ 1.16 +PRIOMethods _pr_faulty_methods = { 1.17 + (PRDescType)0, 1.18 + (PRCloseFN)_PR_InvalidStatus, 1.19 + (PRReadFN)_PR_InvalidInt, 1.20 + (PRWriteFN)_PR_InvalidInt, 1.21 + (PRAvailableFN)_PR_InvalidInt, 1.22 + (PRAvailable64FN)_PR_InvalidInt64, 1.23 + (PRFsyncFN)_PR_InvalidStatus, 1.24 + (PRSeekFN)_PR_InvalidInt, 1.25 + (PRSeek64FN)_PR_InvalidInt64, 1.26 + (PRFileInfoFN)_PR_InvalidStatus, 1.27 + (PRFileInfo64FN)_PR_InvalidStatus, 1.28 + (PRWritevFN)_PR_InvalidInt, 1.29 + (PRConnectFN)_PR_InvalidStatus, 1.30 + (PRAcceptFN)_PR_InvalidDesc, 1.31 + (PRBindFN)_PR_InvalidStatus, 1.32 + (PRListenFN)_PR_InvalidStatus, 1.33 + (PRShutdownFN)_PR_InvalidStatus, 1.34 + (PRRecvFN)_PR_InvalidInt, 1.35 + (PRSendFN)_PR_InvalidInt, 1.36 + (PRRecvfromFN)_PR_InvalidInt, 1.37 + (PRSendtoFN)_PR_InvalidInt, 1.38 + (PRPollFN)_PR_InvalidInt16, 1.39 + (PRAcceptreadFN)_PR_InvalidInt, 1.40 + (PRTransmitfileFN)_PR_InvalidInt, 1.41 + (PRGetsocknameFN)_PR_InvalidStatus, 1.42 + (PRGetpeernameFN)_PR_InvalidStatus, 1.43 + (PRReservedFN)_PR_InvalidInt, 1.44 + (PRReservedFN)_PR_InvalidInt, 1.45 + (PRGetsocketoptionFN)_PR_InvalidStatus, 1.46 + (PRSetsocketoptionFN)_PR_InvalidStatus, 1.47 + (PRSendfileFN)_PR_InvalidInt, 1.48 + (PRConnectcontinueFN)_PR_InvalidStatus, 1.49 + (PRReservedFN)_PR_InvalidInt, 1.50 + (PRReservedFN)_PR_InvalidInt, 1.51 + (PRReservedFN)_PR_InvalidInt, 1.52 + (PRReservedFN)_PR_InvalidInt 1.53 +}; 1.54 + 1.55 +PRIntn _PR_InvalidInt(void) 1.56 +{ 1.57 + PR_ASSERT(!"I/O method is invalid"); 1.58 + PR_SetError(PR_INVALID_METHOD_ERROR, 0); 1.59 + return -1; 1.60 +} /* _PR_InvalidInt */ 1.61 + 1.62 +PRInt16 _PR_InvalidInt16(void) 1.63 +{ 1.64 + PR_ASSERT(!"I/O method is invalid"); 1.65 + PR_SetError(PR_INVALID_METHOD_ERROR, 0); 1.66 + return -1; 1.67 +} /* _PR_InvalidInt */ 1.68 + 1.69 +PRInt64 _PR_InvalidInt64(void) 1.70 +{ 1.71 + PRInt64 rv; 1.72 + LL_I2L(rv, -1); 1.73 + PR_ASSERT(!"I/O method is invalid"); 1.74 + PR_SetError(PR_INVALID_METHOD_ERROR, 0); 1.75 + return rv; 1.76 +} /* _PR_InvalidInt */ 1.77 + 1.78 +/* 1.79 + * An invalid method that returns PRStatus 1.80 + */ 1.81 + 1.82 +PRStatus _PR_InvalidStatus(void) 1.83 +{ 1.84 + PR_ASSERT(!"I/O method is invalid"); 1.85 + PR_SetError(PR_INVALID_METHOD_ERROR, 0); 1.86 + return PR_FAILURE; 1.87 +} /* _PR_InvalidDesc */ 1.88 + 1.89 +/* 1.90 + * An invalid method that returns a pointer 1.91 + */ 1.92 + 1.93 +PRFileDesc *_PR_InvalidDesc(void) 1.94 +{ 1.95 + PR_ASSERT(!"I/O method is invalid"); 1.96 + PR_SetError(PR_INVALID_METHOD_ERROR, 0); 1.97 + return NULL; 1.98 +} /* _PR_InvalidDesc */ 1.99 + 1.100 +PR_IMPLEMENT(PRDescType) PR_GetDescType(PRFileDesc *file) 1.101 +{ 1.102 + return file->methods->file_type; 1.103 +} 1.104 + 1.105 +PR_IMPLEMENT(PRStatus) PR_Close(PRFileDesc *fd) 1.106 +{ 1.107 + return (fd->methods->close)(fd); 1.108 +} 1.109 + 1.110 +PR_IMPLEMENT(PRInt32) PR_Read(PRFileDesc *fd, void *buf, PRInt32 amount) 1.111 +{ 1.112 + return((fd->methods->read)(fd,buf,amount)); 1.113 +} 1.114 + 1.115 +PR_IMPLEMENT(PRInt32) PR_Write(PRFileDesc *fd, const void *buf, PRInt32 amount) 1.116 +{ 1.117 + return((fd->methods->write)(fd,buf,amount)); 1.118 +} 1.119 + 1.120 +PR_IMPLEMENT(PRInt32) PR_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence) 1.121 +{ 1.122 + return((fd->methods->seek)(fd, offset, whence)); 1.123 +} 1.124 + 1.125 +PR_IMPLEMENT(PRInt64) PR_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence) 1.126 +{ 1.127 + return((fd->methods->seek64)(fd, offset, whence)); 1.128 +} 1.129 + 1.130 +PR_IMPLEMENT(PRInt32) PR_Available(PRFileDesc *fd) 1.131 +{ 1.132 + return((fd->methods->available)(fd)); 1.133 +} 1.134 + 1.135 +PR_IMPLEMENT(PRInt64) PR_Available64(PRFileDesc *fd) 1.136 +{ 1.137 + return((fd->methods->available64)(fd)); 1.138 +} 1.139 + 1.140 +PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo(PRFileDesc *fd, PRFileInfo *info) 1.141 +{ 1.142 + return((fd->methods->fileInfo)(fd, info)); 1.143 +} 1.144 + 1.145 +PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo64(PRFileDesc *fd, PRFileInfo64 *info) 1.146 +{ 1.147 + return((fd->methods->fileInfo64)(fd, info)); 1.148 +} 1.149 + 1.150 +PR_IMPLEMENT(PRStatus) PR_Sync(PRFileDesc *fd) 1.151 +{ 1.152 + return((fd->methods->fsync)(fd)); 1.153 +} 1.154 + 1.155 +PR_IMPLEMENT(PRStatus) PR_Connect( 1.156 + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) 1.157 +{ 1.158 + return((fd->methods->connect)(fd,addr,timeout)); 1.159 +} 1.160 + 1.161 +PR_IMPLEMENT(PRStatus) PR_ConnectContinue( 1.162 + PRFileDesc *fd, PRInt16 out_flags) 1.163 +{ 1.164 + return((fd->methods->connectcontinue)(fd,out_flags)); 1.165 +} 1.166 + 1.167 +PR_IMPLEMENT(PRFileDesc*) PR_Accept(PRFileDesc *fd, PRNetAddr *addr, 1.168 +PRIntervalTime timeout) 1.169 +{ 1.170 + return((fd->methods->accept)(fd,addr,timeout)); 1.171 +} 1.172 + 1.173 +PR_IMPLEMENT(PRStatus) PR_Bind(PRFileDesc *fd, const PRNetAddr *addr) 1.174 +{ 1.175 + return((fd->methods->bind)(fd,addr)); 1.176 +} 1.177 + 1.178 +PR_IMPLEMENT(PRStatus) PR_Shutdown(PRFileDesc *fd, PRShutdownHow how) 1.179 +{ 1.180 + return((fd->methods->shutdown)(fd,how)); 1.181 +} 1.182 + 1.183 +PR_IMPLEMENT(PRStatus) PR_Listen(PRFileDesc *fd, PRIntn backlog) 1.184 +{ 1.185 + return((fd->methods->listen)(fd,backlog)); 1.186 +} 1.187 + 1.188 +PR_IMPLEMENT(PRInt32) PR_Recv(PRFileDesc *fd, void *buf, PRInt32 amount, 1.189 +PRIntn flags, PRIntervalTime timeout) 1.190 +{ 1.191 + return((fd->methods->recv)(fd,buf,amount,flags,timeout)); 1.192 +} 1.193 + 1.194 +PR_IMPLEMENT(PRInt32) PR_Send(PRFileDesc *fd, const void *buf, PRInt32 amount, 1.195 +PRIntn flags, PRIntervalTime timeout) 1.196 +{ 1.197 + return((fd->methods->send)(fd,buf,amount,flags,timeout)); 1.198 +} 1.199 + 1.200 +PR_IMPLEMENT(PRInt32) PR_Writev(PRFileDesc *fd, const PRIOVec *iov, 1.201 +PRInt32 iov_size, PRIntervalTime timeout) 1.202 +{ 1.203 + if (iov_size > PR_MAX_IOVECTOR_SIZE) 1.204 + { 1.205 + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); 1.206 + return -1; 1.207 + } 1.208 + return((fd->methods->writev)(fd,iov,iov_size,timeout)); 1.209 +} 1.210 + 1.211 +PR_IMPLEMENT(PRInt32) PR_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount, 1.212 +PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout) 1.213 +{ 1.214 + return((fd->methods->recvfrom)(fd,buf,amount,flags,addr,timeout)); 1.215 +} 1.216 + 1.217 +PR_IMPLEMENT(PRInt32) PR_SendTo( 1.218 + PRFileDesc *fd, const void *buf, PRInt32 amount, 1.219 + PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout) 1.220 +{ 1.221 + return((fd->methods->sendto)(fd,buf,amount,flags,addr,timeout)); 1.222 +} 1.223 + 1.224 +PR_IMPLEMENT(PRInt32) PR_TransmitFile( 1.225 + PRFileDesc *sd, PRFileDesc *fd, const void *hdr, PRInt32 hlen, 1.226 + PRTransmitFileFlags flags, PRIntervalTime timeout) 1.227 +{ 1.228 + return((sd->methods->transmitfile)(sd,fd,hdr,hlen,flags,timeout)); 1.229 +} 1.230 + 1.231 +PR_IMPLEMENT(PRInt32) PR_AcceptRead( 1.232 + PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, 1.233 + void *buf, PRInt32 amount, PRIntervalTime timeout) 1.234 +{ 1.235 + return((sd->methods->acceptread)(sd, nd, raddr, buf, amount,timeout)); 1.236 +} 1.237 + 1.238 +PR_IMPLEMENT(PRStatus) PR_GetSockName(PRFileDesc *fd, PRNetAddr *addr) 1.239 +{ 1.240 + return((fd->methods->getsockname)(fd,addr)); 1.241 +} 1.242 + 1.243 +PR_IMPLEMENT(PRStatus) PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr) 1.244 +{ 1.245 + return((fd->methods->getpeername)(fd,addr)); 1.246 +} 1.247 + 1.248 +PR_IMPLEMENT(PRStatus) PR_GetSocketOption( 1.249 + PRFileDesc *fd, PRSocketOptionData *data) 1.250 +{ 1.251 + return((fd->methods->getsocketoption)(fd, data)); 1.252 +} 1.253 + 1.254 +PR_IMPLEMENT(PRStatus) PR_SetSocketOption( 1.255 + PRFileDesc *fd, const PRSocketOptionData *data) 1.256 +{ 1.257 + return((fd->methods->setsocketoption)(fd, data)); 1.258 +} 1.259 + 1.260 +PR_IMPLEMENT(PRInt32) PR_SendFile( 1.261 + PRFileDesc *sd, PRSendFileData *sfd, 1.262 + PRTransmitFileFlags flags, PRIntervalTime timeout) 1.263 +{ 1.264 + return((sd->methods->sendfile)(sd,sfd,flags,timeout)); 1.265 +} 1.266 + 1.267 +PR_IMPLEMENT(PRInt32) PR_EmulateAcceptRead( 1.268 + PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, 1.269 + void *buf, PRInt32 amount, PRIntervalTime timeout) 1.270 +{ 1.271 + PRInt32 rv = -1; 1.272 + PRNetAddr remote; 1.273 + PRFileDesc *accepted = NULL; 1.274 + 1.275 + /* 1.276 + ** The timeout does not apply to the accept portion of the 1.277 + ** operation - it waits indefinitely. 1.278 + */ 1.279 + accepted = PR_Accept(sd, &remote, PR_INTERVAL_NO_TIMEOUT); 1.280 + if (NULL == accepted) return rv; 1.281 + 1.282 + rv = PR_Recv(accepted, buf, amount, 0, timeout); 1.283 + if (rv >= 0) 1.284 + { 1.285 + /* copy the new info out where caller can see it */ 1.286 +#define AMASK ((PRPtrdiff)7) /* mask for alignment of PRNetAddr */ 1.287 + PRPtrdiff aligned = (PRPtrdiff)buf + amount + AMASK; 1.288 + *raddr = (PRNetAddr*)(aligned & ~AMASK); 1.289 + memcpy(*raddr, &remote, PR_NETADDR_SIZE(&remote)); 1.290 + *nd = accepted; 1.291 + return rv; 1.292 + } 1.293 + 1.294 + PR_Close(accepted); 1.295 + return rv; 1.296 +} 1.297 + 1.298 +/* 1.299 + * PR_EmulateSendFile 1.300 + * 1.301 + * Send file sfd->fd across socket sd. If header/trailer are specified 1.302 + * they are sent before and after the file, respectively. 1.303 + * 1.304 + * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file 1.305 + * 1.306 + * return number of bytes sent or -1 on error 1.307 + * 1.308 + */ 1.309 + 1.310 +#if defined(XP_UNIX) || defined(WIN32) 1.311 + 1.312 +/* 1.313 + * An implementation based on memory-mapped files 1.314 + */ 1.315 + 1.316 +#define SENDFILE_MMAP_CHUNK (256 * 1024) 1.317 + 1.318 +PR_IMPLEMENT(PRInt32) PR_EmulateSendFile( 1.319 + PRFileDesc *sd, PRSendFileData *sfd, 1.320 + PRTransmitFileFlags flags, PRIntervalTime timeout) 1.321 +{ 1.322 + PRInt32 rv, count = 0; 1.323 + PRInt32 len, file_bytes, index = 0; 1.324 + PRFileInfo info; 1.325 + PRIOVec iov[3]; 1.326 + PRFileMap *mapHandle = NULL; 1.327 + void *addr = (void*)0; /* initialized to some arbitrary value. Keeps compiler warnings down. */ 1.328 + PRUint32 file_mmap_offset, alignment; 1.329 + PRInt64 zero64; 1.330 + PROffset64 file_mmap_offset64; 1.331 + PRUint32 addr_offset, mmap_len; 1.332 + 1.333 + /* Get file size */ 1.334 + if (PR_SUCCESS != PR_GetOpenFileInfo(sfd->fd, &info)) { 1.335 + count = -1; 1.336 + goto done; 1.337 + } 1.338 + if (sfd->file_nbytes && 1.339 + (info.size < (sfd->file_offset + sfd->file_nbytes))) { 1.340 + /* 1.341 + * there are fewer bytes in file to send than specified 1.342 + */ 1.343 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.344 + count = -1; 1.345 + goto done; 1.346 + } 1.347 + if (sfd->file_nbytes) 1.348 + file_bytes = sfd->file_nbytes; 1.349 + else 1.350 + file_bytes = info.size - sfd->file_offset; 1.351 + 1.352 + alignment = PR_GetMemMapAlignment(); 1.353 + 1.354 + /* number of initial bytes to skip in mmap'd segment */ 1.355 + addr_offset = sfd->file_offset % alignment; 1.356 + 1.357 + /* find previous mmap alignment boundary */ 1.358 + file_mmap_offset = sfd->file_offset - addr_offset; 1.359 + 1.360 + /* 1.361 + * If the file is large, mmap and send the file in chunks so as 1.362 + * to not consume too much virtual address space 1.363 + */ 1.364 + mmap_len = PR_MIN(file_bytes + addr_offset, SENDFILE_MMAP_CHUNK); 1.365 + len = mmap_len - addr_offset; 1.366 + 1.367 + /* 1.368 + * Map in (part of) file. Take care of zero-length files. 1.369 + */ 1.370 + if (len) { 1.371 + LL_I2L(zero64, 0); 1.372 + mapHandle = PR_CreateFileMap(sfd->fd, zero64, PR_PROT_READONLY); 1.373 + if (!mapHandle) { 1.374 + count = -1; 1.375 + goto done; 1.376 + } 1.377 + LL_I2L(file_mmap_offset64, file_mmap_offset); 1.378 + addr = PR_MemMap(mapHandle, file_mmap_offset64, mmap_len); 1.379 + if (!addr) { 1.380 + count = -1; 1.381 + goto done; 1.382 + } 1.383 + } 1.384 + /* 1.385 + * send headers first, followed by the file 1.386 + */ 1.387 + if (sfd->hlen) { 1.388 + iov[index].iov_base = (char *) sfd->header; 1.389 + iov[index].iov_len = sfd->hlen; 1.390 + index++; 1.391 + } 1.392 + if (len) { 1.393 + iov[index].iov_base = (char*)addr + addr_offset; 1.394 + iov[index].iov_len = len; 1.395 + index++; 1.396 + } 1.397 + if ((file_bytes == len) && (sfd->tlen)) { 1.398 + /* 1.399 + * all file data is mapped in; send the trailer too 1.400 + */ 1.401 + iov[index].iov_base = (char *) sfd->trailer; 1.402 + iov[index].iov_len = sfd->tlen; 1.403 + index++; 1.404 + } 1.405 + rv = PR_Writev(sd, iov, index, timeout); 1.406 + if (len) 1.407 + PR_MemUnmap(addr, mmap_len); 1.408 + if (rv < 0) { 1.409 + count = -1; 1.410 + goto done; 1.411 + } 1.412 + 1.413 + PR_ASSERT(rv == sfd->hlen + len + ((len == file_bytes) ? sfd->tlen : 0)); 1.414 + 1.415 + file_bytes -= len; 1.416 + count += rv; 1.417 + if (!file_bytes) /* header, file and trailer are sent */ 1.418 + goto done; 1.419 + 1.420 + /* 1.421 + * send remaining bytes of the file, if any 1.422 + */ 1.423 + len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK); 1.424 + while (len > 0) { 1.425 + /* 1.426 + * Map in (part of) file 1.427 + */ 1.428 + file_mmap_offset = sfd->file_offset + count - sfd->hlen; 1.429 + PR_ASSERT((file_mmap_offset % alignment) == 0); 1.430 + 1.431 + LL_I2L(file_mmap_offset64, file_mmap_offset); 1.432 + addr = PR_MemMap(mapHandle, file_mmap_offset64, len); 1.433 + if (!addr) { 1.434 + count = -1; 1.435 + goto done; 1.436 + } 1.437 + rv = PR_Send(sd, addr, len, 0, timeout); 1.438 + PR_MemUnmap(addr, len); 1.439 + if (rv < 0) { 1.440 + count = -1; 1.441 + goto done; 1.442 + } 1.443 + 1.444 + PR_ASSERT(rv == len); 1.445 + file_bytes -= rv; 1.446 + count += rv; 1.447 + len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK); 1.448 + } 1.449 + PR_ASSERT(0 == file_bytes); 1.450 + if (sfd->tlen) { 1.451 + rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout); 1.452 + if (rv >= 0) { 1.453 + PR_ASSERT(rv == sfd->tlen); 1.454 + count += rv; 1.455 + } else 1.456 + count = -1; 1.457 + } 1.458 +done: 1.459 + if (mapHandle) 1.460 + PR_CloseFileMap(mapHandle); 1.461 + if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) 1.462 + PR_Close(sd); 1.463 + return count; 1.464 +} 1.465 + 1.466 +#else 1.467 + 1.468 +PR_IMPLEMENT(PRInt32) PR_EmulateSendFile( 1.469 + PRFileDesc *sd, PRSendFileData *sfd, 1.470 + PRTransmitFileFlags flags, PRIntervalTime timeout) 1.471 +{ 1.472 + PRInt32 rv, count = 0; 1.473 + PRInt32 rlen; 1.474 + const void * buffer; 1.475 + PRInt32 buflen; 1.476 + PRInt32 sendbytes, readbytes; 1.477 + char *buf; 1.478 + 1.479 +#define _SENDFILE_BUFSIZE (16 * 1024) 1.480 + 1.481 + buf = (char*)PR_MALLOC(_SENDFILE_BUFSIZE); 1.482 + if (buf == NULL) { 1.483 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.484 + return -1; 1.485 + } 1.486 + 1.487 + /* 1.488 + * send header first 1.489 + */ 1.490 + buflen = sfd->hlen; 1.491 + buffer = sfd->header; 1.492 + while (buflen) { 1.493 + rv = PR_Send(sd, buffer, buflen, 0, timeout); 1.494 + if (rv < 0) { 1.495 + /* PR_Send() has invoked PR_SetError(). */ 1.496 + rv = -1; 1.497 + goto done; 1.498 + } else { 1.499 + count += rv; 1.500 + buffer = (const void*) ((const char*)buffer + rv); 1.501 + buflen -= rv; 1.502 + } 1.503 + } 1.504 + 1.505 + /* 1.506 + * send file next 1.507 + */ 1.508 + if (PR_Seek(sfd->fd, sfd->file_offset, PR_SEEK_SET) < 0) { 1.509 + rv = -1; 1.510 + goto done; 1.511 + } 1.512 + sendbytes = sfd->file_nbytes; 1.513 + if (sendbytes == 0) { 1.514 + /* send entire file */ 1.515 + while ((rlen = PR_Read(sfd->fd, buf, _SENDFILE_BUFSIZE)) > 0) { 1.516 + while (rlen) { 1.517 + char *bufptr = buf; 1.518 + 1.519 + rv = PR_Send(sd, bufptr, rlen, 0, timeout); 1.520 + if (rv < 0) { 1.521 + /* PR_Send() has invoked PR_SetError(). */ 1.522 + rv = -1; 1.523 + goto done; 1.524 + } else { 1.525 + count += rv; 1.526 + bufptr = ((char*)bufptr + rv); 1.527 + rlen -= rv; 1.528 + } 1.529 + } 1.530 + } 1.531 + if (rlen < 0) { 1.532 + /* PR_Read() has invoked PR_SetError(). */ 1.533 + rv = -1; 1.534 + goto done; 1.535 + } 1.536 + } else { 1.537 + readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE); 1.538 + while (readbytes && ((rlen = PR_Read(sfd->fd, buf, readbytes)) > 0)) { 1.539 + while (rlen) { 1.540 + char *bufptr = buf; 1.541 + 1.542 + rv = PR_Send(sd, bufptr, rlen, 0, timeout); 1.543 + if (rv < 0) { 1.544 + /* PR_Send() has invoked PR_SetError(). */ 1.545 + rv = -1; 1.546 + goto done; 1.547 + } else { 1.548 + count += rv; 1.549 + sendbytes -= rv; 1.550 + bufptr = ((char*)bufptr + rv); 1.551 + rlen -= rv; 1.552 + } 1.553 + } 1.554 + readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE); 1.555 + } 1.556 + if (rlen < 0) { 1.557 + /* PR_Read() has invoked PR_SetError(). */ 1.558 + rv = -1; 1.559 + goto done; 1.560 + } else if (sendbytes != 0) { 1.561 + /* 1.562 + * there are fewer bytes in file to send than specified 1.563 + */ 1.564 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.565 + rv = -1; 1.566 + goto done; 1.567 + } 1.568 + } 1.569 + 1.570 + /* 1.571 + * send trailer last 1.572 + */ 1.573 + buflen = sfd->tlen; 1.574 + buffer = sfd->trailer; 1.575 + while (buflen) { 1.576 + rv = PR_Send(sd, buffer, buflen, 0, timeout); 1.577 + if (rv < 0) { 1.578 + /* PR_Send() has invoked PR_SetError(). */ 1.579 + rv = -1; 1.580 + goto done; 1.581 + } else { 1.582 + count += rv; 1.583 + buffer = (const void*) ((const char*)buffer + rv); 1.584 + buflen -= rv; 1.585 + } 1.586 + } 1.587 + rv = count; 1.588 + 1.589 +done: 1.590 + if (buf) 1.591 + PR_DELETE(buf); 1.592 + if ((rv >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) 1.593 + PR_Close(sd); 1.594 + return rv; 1.595 +} 1.596 + 1.597 +#endif 1.598 + 1.599 +/* priometh.c */