Backed out 2 changesets (bug 1943998) for causing wd failures @ phases.py CLOSED...
[gecko.git] / nsprpub / pr / src / io / priometh.c
blob0b9029b25a42602c0f2a7b019bfbf151a52e43aa
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 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"
8 #include <string.h>
10 /*****************************************************************************/
11 /************************** Invalid I/O method object ************************/
12 /*****************************************************************************/
13 PRIOMethods _pr_faulty_methods = {(PRDescType)0,
14 (PRCloseFN)_PR_InvalidStatus,
15 (PRReadFN)_PR_InvalidInt,
16 (PRWriteFN)_PR_InvalidInt,
17 (PRAvailableFN)_PR_InvalidInt,
18 (PRAvailable64FN)_PR_InvalidInt64,
19 (PRFsyncFN)_PR_InvalidStatus,
20 (PRSeekFN)_PR_InvalidInt,
21 (PRSeek64FN)_PR_InvalidInt64,
22 (PRFileInfoFN)_PR_InvalidStatus,
23 (PRFileInfo64FN)_PR_InvalidStatus,
24 (PRWritevFN)_PR_InvalidInt,
25 (PRConnectFN)_PR_InvalidStatus,
26 (PRAcceptFN)_PR_InvalidDesc,
27 (PRBindFN)_PR_InvalidStatus,
28 (PRListenFN)_PR_InvalidStatus,
29 (PRShutdownFN)_PR_InvalidStatus,
30 (PRRecvFN)_PR_InvalidInt,
31 (PRSendFN)_PR_InvalidInt,
32 (PRRecvfromFN)_PR_InvalidInt,
33 (PRSendtoFN)_PR_InvalidInt,
34 (PRPollFN)_PR_InvalidInt16,
35 (PRAcceptreadFN)_PR_InvalidInt,
36 (PRTransmitfileFN)_PR_InvalidInt,
37 (PRGetsocknameFN)_PR_InvalidStatus,
38 (PRGetpeernameFN)_PR_InvalidStatus,
39 (PRReservedFN)_PR_InvalidInt,
40 (PRReservedFN)_PR_InvalidInt,
41 (PRGetsocketoptionFN)_PR_InvalidStatus,
42 (PRSetsocketoptionFN)_PR_InvalidStatus,
43 (PRSendfileFN)_PR_InvalidInt,
44 (PRConnectcontinueFN)_PR_InvalidStatus,
45 (PRReservedFN)_PR_InvalidInt,
46 (PRReservedFN)_PR_InvalidInt,
47 (PRReservedFN)_PR_InvalidInt,
48 (PRReservedFN)_PR_InvalidInt};
50 PRIntn _PR_InvalidInt(void) {
51 PR_NOT_REACHED("I/O method is invalid");
52 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
53 return -1;
54 } /* _PR_InvalidInt */
56 PRInt16 _PR_InvalidInt16(void) {
57 PR_NOT_REACHED("I/O method is invalid");
58 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
59 return -1;
60 } /* _PR_InvalidInt */
62 PRInt64 _PR_InvalidInt64(void) {
63 PRInt64 rv;
64 LL_I2L(rv, -1);
65 PR_NOT_REACHED("I/O method is invalid");
66 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
67 return rv;
68 } /* _PR_InvalidInt */
71 * An invalid method that returns PRStatus
74 PRStatus _PR_InvalidStatus(void) {
75 PR_NOT_REACHED("I/O method is invalid");
76 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
77 return PR_FAILURE;
78 } /* _PR_InvalidDesc */
81 * An invalid method that returns a pointer
84 PRFileDesc* _PR_InvalidDesc(void) {
85 PR_NOT_REACHED("I/O method is invalid");
86 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
87 return NULL;
88 } /* _PR_InvalidDesc */
90 PR_IMPLEMENT(PRDescType) PR_GetDescType(PRFileDesc* file) {
91 return file->methods->file_type;
94 PR_IMPLEMENT(PRStatus) PR_Close(PRFileDesc* fd) {
95 return (fd->methods->close)(fd);
98 PR_IMPLEMENT(PRInt32) PR_Read(PRFileDesc* fd, void* buf, PRInt32 amount) {
99 return ((fd->methods->read)(fd, buf, amount));
102 PR_IMPLEMENT(PRInt32)
103 PR_Write(PRFileDesc* fd, const void* buf, PRInt32 amount) {
104 return ((fd->methods->write)(fd, buf, amount));
107 PR_IMPLEMENT(PRInt32)
108 PR_Seek(PRFileDesc* fd, PRInt32 offset, PRSeekWhence whence) {
109 return ((fd->methods->seek)(fd, offset, whence));
112 PR_IMPLEMENT(PRInt64)
113 PR_Seek64(PRFileDesc* fd, PRInt64 offset, PRSeekWhence whence) {
114 return ((fd->methods->seek64)(fd, offset, whence));
117 PR_IMPLEMENT(PRInt32) PR_Available(PRFileDesc* fd) {
118 return ((fd->methods->available)(fd));
121 PR_IMPLEMENT(PRInt64) PR_Available64(PRFileDesc* fd) {
122 return ((fd->methods->available64)(fd));
125 PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo(PRFileDesc* fd, PRFileInfo* info) {
126 return ((fd->methods->fileInfo)(fd, info));
129 PR_IMPLEMENT(PRStatus)
130 PR_GetOpenFileInfo64(PRFileDesc* fd, PRFileInfo64* info) {
131 return ((fd->methods->fileInfo64)(fd, info));
134 PR_IMPLEMENT(PRStatus) PR_Sync(PRFileDesc* fd) {
135 return ((fd->methods->fsync)(fd));
138 PR_IMPLEMENT(PRStatus)
139 PR_Connect(PRFileDesc* fd, const PRNetAddr* addr, PRIntervalTime timeout) {
140 return ((fd->methods->connect)(fd, addr, timeout));
143 PR_IMPLEMENT(PRStatus) PR_ConnectContinue(PRFileDesc* fd, PRInt16 out_flags) {
144 return ((fd->methods->connectcontinue)(fd, out_flags));
147 PR_IMPLEMENT(PRFileDesc*)
148 PR_Accept(PRFileDesc* fd, PRNetAddr* addr, PRIntervalTime timeout) {
149 return ((fd->methods->accept)(fd, addr, timeout));
152 PR_IMPLEMENT(PRStatus) PR_Bind(PRFileDesc* fd, const PRNetAddr* addr) {
153 return ((fd->methods->bind)(fd, addr));
156 PR_IMPLEMENT(PRStatus) PR_Shutdown(PRFileDesc* fd, PRShutdownHow how) {
157 return ((fd->methods->shutdown)(fd, how));
160 PR_IMPLEMENT(PRStatus) PR_Listen(PRFileDesc* fd, PRIntn backlog) {
161 return ((fd->methods->listen)(fd, backlog));
164 PR_IMPLEMENT(PRInt32)
165 PR_Recv(PRFileDesc* fd, void* buf, PRInt32 amount, PRIntn flags,
166 PRIntervalTime timeout) {
167 return ((fd->methods->recv)(fd, buf, amount, flags, timeout));
170 PR_IMPLEMENT(PRInt32)
171 PR_Send(PRFileDesc* fd, const void* buf, PRInt32 amount, PRIntn flags,
172 PRIntervalTime timeout) {
173 return ((fd->methods->send)(fd, buf, amount, flags, timeout));
176 PR_IMPLEMENT(PRInt32)
177 PR_Writev(PRFileDesc* fd, const PRIOVec* iov, PRInt32 iov_size,
178 PRIntervalTime timeout) {
179 if (iov_size > PR_MAX_IOVECTOR_SIZE) {
180 PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
181 return -1;
183 return ((fd->methods->writev)(fd, iov, iov_size, timeout));
186 PR_IMPLEMENT(PRInt32)
187 PR_RecvFrom(PRFileDesc* fd, void* buf, PRInt32 amount, PRIntn flags,
188 PRNetAddr* addr, PRIntervalTime timeout) {
189 return ((fd->methods->recvfrom)(fd, buf, amount, flags, addr, timeout));
192 PR_IMPLEMENT(PRInt32)
193 PR_SendTo(PRFileDesc* fd, const void* buf, PRInt32 amount, PRIntn flags,
194 const PRNetAddr* addr, PRIntervalTime timeout) {
195 return ((fd->methods->sendto)(fd, buf, amount, flags, addr, timeout));
198 PR_IMPLEMENT(PRInt32)
199 PR_TransmitFile(PRFileDesc* sd, PRFileDesc* fd, const void* hdr, PRInt32 hlen,
200 PRTransmitFileFlags flags, PRIntervalTime timeout) {
201 return ((sd->methods->transmitfile)(sd, fd, hdr, hlen, flags, timeout));
204 PR_IMPLEMENT(PRInt32)
205 PR_AcceptRead(PRFileDesc* sd, PRFileDesc** nd, PRNetAddr** raddr, void* buf,
206 PRInt32 amount, PRIntervalTime timeout) {
207 return ((sd->methods->acceptread)(sd, nd, raddr, buf, amount, timeout));
210 PR_IMPLEMENT(PRStatus) PR_GetSockName(PRFileDesc* fd, PRNetAddr* addr) {
211 return ((fd->methods->getsockname)(fd, addr));
214 PR_IMPLEMENT(PRStatus) PR_GetPeerName(PRFileDesc* fd, PRNetAddr* addr) {
215 return ((fd->methods->getpeername)(fd, addr));
218 PR_IMPLEMENT(PRStatus)
219 PR_GetSocketOption(PRFileDesc* fd, PRSocketOptionData* data) {
220 return ((fd->methods->getsocketoption)(fd, data));
223 PR_IMPLEMENT(PRStatus)
224 PR_SetSocketOption(PRFileDesc* fd, const PRSocketOptionData* data) {
225 return ((fd->methods->setsocketoption)(fd, data));
228 PR_IMPLEMENT(PRInt32)
229 PR_SendFile(PRFileDesc* sd, PRSendFileData* sfd, PRTransmitFileFlags flags,
230 PRIntervalTime timeout) {
231 return ((sd->methods->sendfile)(sd, sfd, flags, timeout));
234 PR_IMPLEMENT(PRInt32)
235 PR_EmulateAcceptRead(PRFileDesc* sd, PRFileDesc** nd, PRNetAddr** raddr,
236 void* buf, PRInt32 amount, PRIntervalTime timeout) {
237 PRInt32 rv = -1;
238 PRNetAddr remote;
239 PRFileDesc* accepted = NULL;
242 ** The timeout does not apply to the accept portion of the
243 ** operation - it waits indefinitely.
245 accepted = PR_Accept(sd, &remote, PR_INTERVAL_NO_TIMEOUT);
246 if (NULL == accepted) {
247 return rv;
250 rv = PR_Recv(accepted, buf, amount, 0, timeout);
251 if (rv >= 0) {
252 /* copy the new info out where caller can see it */
253 #define AMASK ((PRPtrdiff)7) /* mask for alignment of PRNetAddr */
254 PRPtrdiff aligned = (PRPtrdiff)buf + amount + AMASK;
255 *raddr = (PRNetAddr*)(aligned & ~AMASK);
256 memcpy(*raddr, &remote, PR_NETADDR_SIZE(&remote));
257 *nd = accepted;
258 return rv;
261 PR_Close(accepted);
262 return rv;
266 * PR_EmulateSendFile
268 * Send file sfd->fd across socket sd. If header/trailer are specified
269 * they are sent before and after the file, respectively.
271 * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
273 * return number of bytes sent or -1 on error
277 #if defined(XP_UNIX) || defined(WIN32)
280 * An implementation based on memory-mapped files
283 # define SENDFILE_MMAP_CHUNK (256 * 1024)
285 PR_IMPLEMENT(PRInt32)
286 PR_EmulateSendFile(PRFileDesc* sd, PRSendFileData* sfd,
287 PRTransmitFileFlags flags, PRIntervalTime timeout) {
288 PRInt32 rv, count = 0;
289 PRInt32 len, file_bytes, index = 0;
290 PRFileInfo info;
291 PRIOVec iov[3];
292 PRFileMap* mapHandle = NULL;
293 void* addr = (void*)0; /* initialized to some arbitrary value. Keeps compiler
294 warnings down. */
295 PRUint32 file_mmap_offset, alignment;
296 PRInt64 zero64;
297 PROffset64 file_mmap_offset64;
298 PRUint32 addr_offset, mmap_len;
300 /* Get file size */
301 if (PR_SUCCESS != PR_GetOpenFileInfo(sfd->fd, &info)) {
302 count = -1;
303 goto done;
305 if (sfd->file_nbytes && (info.size < (sfd->file_offset + sfd->file_nbytes))) {
307 * there are fewer bytes in file to send than specified
309 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
310 count = -1;
311 goto done;
313 if (sfd->file_nbytes) {
314 file_bytes = sfd->file_nbytes;
315 } else {
316 file_bytes = info.size - sfd->file_offset;
319 alignment = PR_GetMemMapAlignment();
321 /* number of initial bytes to skip in mmap'd segment */
322 addr_offset = sfd->file_offset % alignment;
324 /* find previous mmap alignment boundary */
325 file_mmap_offset = sfd->file_offset - addr_offset;
328 * If the file is large, mmap and send the file in chunks so as
329 * to not consume too much virtual address space
331 mmap_len = PR_MIN(file_bytes + addr_offset, SENDFILE_MMAP_CHUNK);
332 len = mmap_len - addr_offset;
335 * Map in (part of) file. Take care of zero-length files.
337 if (len) {
338 LL_I2L(zero64, 0);
339 mapHandle = PR_CreateFileMap(sfd->fd, zero64, PR_PROT_READONLY);
340 if (!mapHandle) {
341 count = -1;
342 goto done;
344 LL_I2L(file_mmap_offset64, file_mmap_offset);
345 addr = PR_MemMap(mapHandle, file_mmap_offset64, mmap_len);
346 if (!addr) {
347 count = -1;
348 goto done;
352 * send headers first, followed by the file
354 if (sfd->hlen) {
355 iov[index].iov_base = (char*)sfd->header;
356 iov[index].iov_len = sfd->hlen;
357 index++;
359 if (len) {
360 iov[index].iov_base = (char*)addr + addr_offset;
361 iov[index].iov_len = len;
362 index++;
364 if ((file_bytes == len) && (sfd->tlen)) {
366 * all file data is mapped in; send the trailer too
368 iov[index].iov_base = (char*)sfd->trailer;
369 iov[index].iov_len = sfd->tlen;
370 index++;
372 rv = PR_Writev(sd, iov, index, timeout);
373 if (len) {
374 PR_MemUnmap(addr, mmap_len);
376 if (rv < 0) {
377 count = -1;
378 goto done;
381 PR_ASSERT(rv == sfd->hlen + len + ((len == file_bytes) ? sfd->tlen : 0));
383 file_bytes -= len;
384 count += rv;
385 if (!file_bytes) { /* header, file and trailer are sent */
386 goto done;
390 * send remaining bytes of the file, if any
392 len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
393 while (len > 0) {
395 * Map in (part of) file
397 file_mmap_offset = sfd->file_offset + count - sfd->hlen;
398 PR_ASSERT((file_mmap_offset % alignment) == 0);
400 LL_I2L(file_mmap_offset64, file_mmap_offset);
401 addr = PR_MemMap(mapHandle, file_mmap_offset64, len);
402 if (!addr) {
403 count = -1;
404 goto done;
406 rv = PR_Send(sd, addr, len, 0, timeout);
407 PR_MemUnmap(addr, len);
408 if (rv < 0) {
409 count = -1;
410 goto done;
413 PR_ASSERT(rv == len);
414 file_bytes -= rv;
415 count += rv;
416 len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
418 PR_ASSERT(0 == file_bytes);
419 if (sfd->tlen) {
420 rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
421 if (rv >= 0) {
422 PR_ASSERT(rv == sfd->tlen);
423 count += rv;
424 } else {
425 count = -1;
428 done:
429 if (mapHandle) {
430 PR_CloseFileMap(mapHandle);
432 if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) {
433 PR_Close(sd);
435 return count;
438 #else
440 PR_IMPLEMENT(PRInt32)
441 PR_EmulateSendFile(PRFileDesc* sd, PRSendFileData* sfd,
442 PRTransmitFileFlags flags, PRIntervalTime timeout) {
443 PRInt32 rv, count = 0;
444 PRInt32 rlen;
445 const void* buffer;
446 PRInt32 buflen;
447 PRInt32 sendbytes, readbytes;
448 char* buf;
450 # define _SENDFILE_BUFSIZE (16 * 1024)
452 buf = (char*)PR_MALLOC(_SENDFILE_BUFSIZE);
453 if (buf == NULL) {
454 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
455 return -1;
459 * send header first
461 buflen = sfd->hlen;
462 buffer = sfd->header;
463 while (buflen) {
464 rv = PR_Send(sd, buffer, buflen, 0, timeout);
465 if (rv < 0) {
466 /* PR_Send() has invoked PR_SetError(). */
467 rv = -1;
468 goto done;
469 } else {
470 count += rv;
471 buffer = (const void*)((const char*)buffer + rv);
472 buflen -= rv;
477 * send file next
479 if (PR_Seek(sfd->fd, sfd->file_offset, PR_SEEK_SET) < 0) {
480 rv = -1;
481 goto done;
483 sendbytes = sfd->file_nbytes;
484 if (sendbytes == 0) {
485 /* send entire file */
486 while ((rlen = PR_Read(sfd->fd, buf, _SENDFILE_BUFSIZE)) > 0) {
487 while (rlen) {
488 char* bufptr = buf;
490 rv = PR_Send(sd, bufptr, rlen, 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 bufptr = ((char*)bufptr + rv);
498 rlen -= rv;
502 if (rlen < 0) {
503 /* PR_Read() has invoked PR_SetError(). */
504 rv = -1;
505 goto done;
507 } else {
508 readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE);
509 while (readbytes && ((rlen = PR_Read(sfd->fd, buf, readbytes)) > 0)) {
510 while (rlen) {
511 char* bufptr = buf;
513 rv = PR_Send(sd, bufptr, rlen, 0, timeout);
514 if (rv < 0) {
515 /* PR_Send() has invoked PR_SetError(). */
516 rv = -1;
517 goto done;
518 } else {
519 count += rv;
520 sendbytes -= rv;
521 bufptr = ((char*)bufptr + rv);
522 rlen -= rv;
525 readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE);
527 if (rlen < 0) {
528 /* PR_Read() has invoked PR_SetError(). */
529 rv = -1;
530 goto done;
531 } else if (sendbytes != 0) {
533 * there are fewer bytes in file to send than specified
535 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
536 rv = -1;
537 goto done;
542 * send trailer last
544 buflen = sfd->tlen;
545 buffer = sfd->trailer;
546 while (buflen) {
547 rv = PR_Send(sd, buffer, buflen, 0, timeout);
548 if (rv < 0) {
549 /* PR_Send() has invoked PR_SetError(). */
550 rv = -1;
551 goto done;
552 } else {
553 count += rv;
554 buffer = (const void*)((const char*)buffer + rv);
555 buflen -= rv;
558 rv = count;
560 done:
561 if (buf) {
562 PR_DELETE(buf);
564 if ((rv >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) {
565 PR_Close(sd);
567 return rv;
570 #endif
572 /* priometh.c */