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/. */
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);
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);
60 } /* _PR_InvalidInt */
62 PRInt64
_PR_InvalidInt64(void) {
65 PR_NOT_REACHED("I/O method is invalid");
66 PR_SetError(PR_INVALID_METHOD_ERROR
, 0);
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);
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);
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);
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
) {
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
) {
250 rv
= PR_Recv(accepted
, buf
, amount
, 0, timeout
);
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
));
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;
292 PRFileMap
* mapHandle
= NULL
;
293 void* addr
= (void*)0; /* initialized to some arbitrary value. Keeps compiler
295 PRUint32 file_mmap_offset
, alignment
;
297 PROffset64 file_mmap_offset64
;
298 PRUint32 addr_offset
, mmap_len
;
301 if (PR_SUCCESS
!= PR_GetOpenFileInfo(sfd
->fd
, &info
)) {
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);
313 if (sfd
->file_nbytes
) {
314 file_bytes
= sfd
->file_nbytes
;
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.
339 mapHandle
= PR_CreateFileMap(sfd
->fd
, zero64
, PR_PROT_READONLY
);
344 LL_I2L(file_mmap_offset64
, file_mmap_offset
);
345 addr
= PR_MemMap(mapHandle
, file_mmap_offset64
, mmap_len
);
352 * send headers first, followed by the file
355 iov
[index
].iov_base
= (char*)sfd
->header
;
356 iov
[index
].iov_len
= sfd
->hlen
;
360 iov
[index
].iov_base
= (char*)addr
+ addr_offset
;
361 iov
[index
].iov_len
= len
;
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
;
372 rv
= PR_Writev(sd
, iov
, index
, timeout
);
374 PR_MemUnmap(addr
, mmap_len
);
381 PR_ASSERT(rv
== sfd
->hlen
+ len
+ ((len
== file_bytes
) ? sfd
->tlen
: 0));
385 if (!file_bytes
) { /* header, file and trailer are sent */
390 * send remaining bytes of the file, if any
392 len
= PR_MIN(file_bytes
, SENDFILE_MMAP_CHUNK
);
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
);
406 rv
= PR_Send(sd
, addr
, len
, 0, timeout
);
407 PR_MemUnmap(addr
, len
);
413 PR_ASSERT(rv
== len
);
416 len
= PR_MIN(file_bytes
, SENDFILE_MMAP_CHUNK
);
418 PR_ASSERT(0 == file_bytes
);
420 rv
= PR_Send(sd
, sfd
->trailer
, sfd
->tlen
, 0, timeout
);
422 PR_ASSERT(rv
== sfd
->tlen
);
430 PR_CloseFileMap(mapHandle
);
432 if ((count
>= 0) && (flags
& PR_TRANSMITFILE_CLOSE_SOCKET
)) {
440 PR_IMPLEMENT(PRInt32
)
441 PR_EmulateSendFile(PRFileDesc
* sd
, PRSendFileData
* sfd
,
442 PRTransmitFileFlags flags
, PRIntervalTime timeout
) {
443 PRInt32 rv
, count
= 0;
447 PRInt32 sendbytes
, readbytes
;
450 # define _SENDFILE_BUFSIZE (16 * 1024)
452 buf
= (char*)PR_MALLOC(_SENDFILE_BUFSIZE
);
454 PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
462 buffer
= sfd
->header
;
464 rv
= PR_Send(sd
, buffer
, buflen
, 0, timeout
);
466 /* PR_Send() has invoked PR_SetError(). */
471 buffer
= (const void*)((const char*)buffer
+ rv
);
479 if (PR_Seek(sfd
->fd
, sfd
->file_offset
, PR_SEEK_SET
) < 0) {
483 sendbytes
= sfd
->file_nbytes
;
484 if (sendbytes
== 0) {
485 /* send entire file */
486 while ((rlen
= PR_Read(sfd
->fd
, buf
, _SENDFILE_BUFSIZE
)) > 0) {
490 rv
= PR_Send(sd
, bufptr
, rlen
, 0, timeout
);
492 /* PR_Send() has invoked PR_SetError(). */
497 bufptr
= ((char*)bufptr
+ rv
);
503 /* PR_Read() has invoked PR_SetError(). */
508 readbytes
= PR_MIN(sendbytes
, _SENDFILE_BUFSIZE
);
509 while (readbytes
&& ((rlen
= PR_Read(sfd
->fd
, buf
, readbytes
)) > 0)) {
513 rv
= PR_Send(sd
, bufptr
, rlen
, 0, timeout
);
515 /* PR_Send() has invoked PR_SetError(). */
521 bufptr
= ((char*)bufptr
+ rv
);
525 readbytes
= PR_MIN(sendbytes
, _SENDFILE_BUFSIZE
);
528 /* PR_Read() has invoked PR_SetError(). */
531 } else if (sendbytes
!= 0) {
533 * there are fewer bytes in file to send than specified
535 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
545 buffer
= sfd
->trailer
;
547 rv
= PR_Send(sd
, buffer
, buflen
, 0, timeout
);
549 /* PR_Send() has invoked PR_SetError(). */
554 buffer
= (const void*)((const char*)buffer
+ rv
);
564 if ((rv
>= 0) && (flags
& PR_TRANSMITFILE_CLOSE_SOCKET
)) {