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