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