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