nsprpub/pr/src/io/priometh.c

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

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 */

mercurial