Line data Source code
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 0 : PRIntn _PR_InvalidInt(void)
53 : {
54 0 : PR_NOT_REACHED("I/O method is invalid");
55 0 : PR_SetError(PR_INVALID_METHOD_ERROR, 0);
56 0 : return -1;
57 : } /* _PR_InvalidInt */
58 :
59 0 : PRInt16 _PR_InvalidInt16(void)
60 : {
61 0 : PR_NOT_REACHED("I/O method is invalid");
62 0 : PR_SetError(PR_INVALID_METHOD_ERROR, 0);
63 0 : return -1;
64 : } /* _PR_InvalidInt */
65 :
66 0 : PRInt64 _PR_InvalidInt64(void)
67 : {
68 : PRInt64 rv;
69 0 : LL_I2L(rv, -1);
70 0 : PR_NOT_REACHED("I/O method is invalid");
71 0 : PR_SetError(PR_INVALID_METHOD_ERROR, 0);
72 0 : return rv;
73 : } /* _PR_InvalidInt */
74 :
75 : /*
76 : * An invalid method that returns PRStatus
77 : */
78 :
79 0 : PRStatus _PR_InvalidStatus(void)
80 : {
81 0 : PR_NOT_REACHED("I/O method is invalid");
82 0 : PR_SetError(PR_INVALID_METHOD_ERROR, 0);
83 0 : return PR_FAILURE;
84 : } /* _PR_InvalidDesc */
85 :
86 : /*
87 : * An invalid method that returns a pointer
88 : */
89 :
90 0 : PRFileDesc *_PR_InvalidDesc(void)
91 : {
92 0 : PR_NOT_REACHED("I/O method is invalid");
93 0 : PR_SetError(PR_INVALID_METHOD_ERROR, 0);
94 0 : return NULL;
95 : } /* _PR_InvalidDesc */
96 :
97 : PR_IMPLEMENT(PRDescType) PR_GetDescType(PRFileDesc *file)
98 : {
99 0 : return file->methods->file_type;
100 : }
101 :
102 : PR_IMPLEMENT(PRStatus) PR_Close(PRFileDesc *fd)
103 : {
104 1256 : return (fd->methods->close)(fd);
105 : }
106 :
107 : PR_IMPLEMENT(PRInt32) PR_Read(PRFileDesc *fd, void *buf, PRInt32 amount)
108 : {
109 1296 : return((fd->methods->read)(fd,buf,amount));
110 : }
111 :
112 : PR_IMPLEMENT(PRInt32) PR_Write(PRFileDesc *fd, const void *buf, PRInt32 amount)
113 : {
114 159 : return((fd->methods->write)(fd,buf,amount));
115 : }
116 :
117 : PR_IMPLEMENT(PRInt32) PR_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence)
118 : {
119 2 : return((fd->methods->seek)(fd, offset, whence));
120 : }
121 :
122 : PR_IMPLEMENT(PRInt64) PR_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence)
123 : {
124 11 : return((fd->methods->seek64)(fd, offset, whence));
125 : }
126 :
127 : PR_IMPLEMENT(PRInt32) PR_Available(PRFileDesc *fd)
128 : {
129 3 : return((fd->methods->available)(fd));
130 : }
131 :
132 : PR_IMPLEMENT(PRInt64) PR_Available64(PRFileDesc *fd)
133 : {
134 134 : return((fd->methods->available64)(fd));
135 : }
136 :
137 : PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo(PRFileDesc *fd, PRFileInfo *info)
138 : {
139 1 : return((fd->methods->fileInfo)(fd, info));
140 : }
141 :
142 : PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo64(PRFileDesc *fd, PRFileInfo64 *info)
143 : {
144 941 : return((fd->methods->fileInfo64)(fd, info));
145 : }
146 :
147 : PR_IMPLEMENT(PRStatus) PR_Sync(PRFileDesc *fd)
148 : {
149 6 : return((fd->methods->fsync)(fd));
150 : }
151 :
152 : PR_IMPLEMENT(PRStatus) PR_Connect(
153 : PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
154 : {
155 3 : return((fd->methods->connect)(fd,addr,timeout));
156 : }
157 :
158 : PR_IMPLEMENT(PRStatus) PR_ConnectContinue(
159 : PRFileDesc *fd, PRInt16 out_flags)
160 : {
161 3 : return((fd->methods->connectcontinue)(fd,out_flags));
162 : }
163 :
164 : PR_IMPLEMENT(PRFileDesc*) PR_Accept(PRFileDesc *fd, PRNetAddr *addr,
165 : PRIntervalTime timeout)
166 : {
167 0 : return((fd->methods->accept)(fd,addr,timeout));
168 : }
169 :
170 : PR_IMPLEMENT(PRStatus) PR_Bind(PRFileDesc *fd, const PRNetAddr *addr)
171 : {
172 0 : return((fd->methods->bind)(fd,addr));
173 : }
174 :
175 : PR_IMPLEMENT(PRStatus) PR_Shutdown(PRFileDesc *fd, PRShutdownHow how)
176 : {
177 0 : return((fd->methods->shutdown)(fd,how));
178 : }
179 :
180 : PR_IMPLEMENT(PRStatus) PR_Listen(PRFileDesc *fd, PRIntn backlog)
181 : {
182 0 : 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 1 : 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 0 : 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 0 : if (iov_size > PR_MAX_IOVECTOR_SIZE)
201 : {
202 0 : PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
203 0 : return -1;
204 : }
205 0 : 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 0 : 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 0 : 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 0 : 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 0 : return((sd->methods->acceptread)(sd, nd, raddr, buf, amount,timeout));
233 : }
234 :
235 : PR_IMPLEMENT(PRStatus) PR_GetSockName(PRFileDesc *fd, PRNetAddr *addr)
236 : {
237 3 : return((fd->methods->getsockname)(fd,addr));
238 : }
239 :
240 : PR_IMPLEMENT(PRStatus) PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
241 : {
242 0 : return((fd->methods->getpeername)(fd,addr));
243 : }
244 :
245 : PR_IMPLEMENT(PRStatus) PR_GetSocketOption(
246 : PRFileDesc *fd, PRSocketOptionData *data)
247 : {
248 0 : return((fd->methods->getsocketoption)(fd, data));
249 : }
250 :
251 : PR_IMPLEMENT(PRStatus) PR_SetSocketOption(
252 : PRFileDesc *fd, const PRSocketOptionData *data)
253 : {
254 11 : 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 0 : return((sd->methods->sendfile)(sd,sfd,flags,timeout));
262 : }
263 :
264 0 : PR_IMPLEMENT(PRInt32) PR_EmulateAcceptRead(
265 : PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
266 : void *buf, PRInt32 amount, PRIntervalTime timeout)
267 : {
268 0 : PRInt32 rv = -1;
269 : PRNetAddr remote;
270 0 : PRFileDesc *accepted = NULL;
271 :
272 : /*
273 : ** The timeout does not apply to the accept portion of the
274 : ** operation - it waits indefinitely.
275 : */
276 0 : accepted = PR_Accept(sd, &remote, PR_INTERVAL_NO_TIMEOUT);
277 0 : if (NULL == accepted) return rv;
278 :
279 0 : rv = PR_Recv(accepted, buf, amount, 0, timeout);
280 0 : 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 0 : PRPtrdiff aligned = (PRPtrdiff)buf + amount + AMASK;
285 0 : *raddr = (PRNetAddr*)(aligned & ~AMASK);
286 0 : memcpy(*raddr, &remote, PR_NETADDR_SIZE(&remote));
287 0 : *nd = accepted;
288 0 : return rv;
289 : }
290 :
291 0 : PR_Close(accepted);
292 0 : 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 0 : PR_IMPLEMENT(PRInt32) PR_EmulateSendFile(
316 : PRFileDesc *sd, PRSendFileData *sfd,
317 : PRTransmitFileFlags flags, PRIntervalTime timeout)
318 : {
319 0 : PRInt32 rv, count = 0;
320 0 : PRInt32 len, file_bytes, index = 0;
321 : PRFileInfo info;
322 : PRIOVec iov[3];
323 0 : PRFileMap *mapHandle = NULL;
324 0 : void *addr = (void*)0; /* initialized to some arbitrary value. Keeps compiler 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 0 : if (PR_SUCCESS != PR_GetOpenFileInfo(sfd->fd, &info)) {
332 0 : count = -1;
333 0 : goto done;
334 : }
335 0 : if (sfd->file_nbytes &&
336 0 : (info.size < (sfd->file_offset + sfd->file_nbytes))) {
337 : /*
338 : * there are fewer bytes in file to send than specified
339 : */
340 0 : PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
341 0 : count = -1;
342 0 : goto done;
343 : }
344 0 : if (sfd->file_nbytes)
345 0 : file_bytes = sfd->file_nbytes;
346 : else
347 0 : file_bytes = info.size - sfd->file_offset;
348 :
349 0 : alignment = PR_GetMemMapAlignment();
350 :
351 : /* number of initial bytes to skip in mmap'd segment */
352 0 : addr_offset = sfd->file_offset % alignment;
353 :
354 : /* find previous mmap alignment boundary */
355 0 : 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 0 : mmap_len = PR_MIN(file_bytes + addr_offset, SENDFILE_MMAP_CHUNK);
362 0 : len = mmap_len - addr_offset;
363 :
364 : /*
365 : * Map in (part of) file. Take care of zero-length files.
366 : */
367 0 : if (len) {
368 0 : LL_I2L(zero64, 0);
369 0 : mapHandle = PR_CreateFileMap(sfd->fd, zero64, PR_PROT_READONLY);
370 0 : if (!mapHandle) {
371 0 : count = -1;
372 0 : goto done;
373 : }
374 0 : LL_I2L(file_mmap_offset64, file_mmap_offset);
375 0 : addr = PR_MemMap(mapHandle, file_mmap_offset64, mmap_len);
376 0 : if (!addr) {
377 0 : count = -1;
378 0 : goto done;
379 : }
380 : }
381 : /*
382 : * send headers first, followed by the file
383 : */
384 0 : if (sfd->hlen) {
385 0 : iov[index].iov_base = (char *) sfd->header;
386 0 : iov[index].iov_len = sfd->hlen;
387 0 : index++;
388 : }
389 0 : if (len) {
390 0 : iov[index].iov_base = (char*)addr + addr_offset;
391 0 : iov[index].iov_len = len;
392 0 : index++;
393 : }
394 0 : if ((file_bytes == len) && (sfd->tlen)) {
395 : /*
396 : * all file data is mapped in; send the trailer too
397 : */
398 0 : iov[index].iov_base = (char *) sfd->trailer;
399 0 : iov[index].iov_len = sfd->tlen;
400 0 : index++;
401 : }
402 0 : rv = PR_Writev(sd, iov, index, timeout);
403 0 : if (len)
404 0 : PR_MemUnmap(addr, mmap_len);
405 0 : if (rv < 0) {
406 0 : count = -1;
407 0 : goto done;
408 : }
409 :
410 0 : PR_ASSERT(rv == sfd->hlen + len + ((len == file_bytes) ? sfd->tlen : 0));
411 :
412 0 : file_bytes -= len;
413 0 : count += rv;
414 0 : if (!file_bytes) /* header, file and trailer are sent */
415 0 : goto done;
416 :
417 : /*
418 : * send remaining bytes of the file, if any
419 : */
420 0 : len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
421 0 : while (len > 0) {
422 : /*
423 : * Map in (part of) file
424 : */
425 0 : file_mmap_offset = sfd->file_offset + count - sfd->hlen;
426 0 : PR_ASSERT((file_mmap_offset % alignment) == 0);
427 :
428 0 : LL_I2L(file_mmap_offset64, file_mmap_offset);
429 0 : addr = PR_MemMap(mapHandle, file_mmap_offset64, len);
430 0 : if (!addr) {
431 0 : count = -1;
432 0 : goto done;
433 : }
434 0 : rv = PR_Send(sd, addr, len, 0, timeout);
435 0 : PR_MemUnmap(addr, len);
436 0 : if (rv < 0) {
437 0 : count = -1;
438 0 : goto done;
439 : }
440 :
441 0 : PR_ASSERT(rv == len);
442 0 : file_bytes -= rv;
443 0 : count += rv;
444 0 : len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
445 : }
446 0 : PR_ASSERT(0 == file_bytes);
447 0 : if (sfd->tlen) {
448 0 : rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
449 0 : if (rv >= 0) {
450 0 : PR_ASSERT(rv == sfd->tlen);
451 0 : count += rv;
452 : } else
453 0 : count = -1;
454 : }
455 : done:
456 0 : if (mapHandle)
457 0 : PR_CloseFileMap(mapHandle);
458 0 : if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET))
459 0 : PR_Close(sd);
460 0 : 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 */
|