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