Coverage Report

Created: 2024-05-20 06:23

/src/nspr/pr/src/io/priometh.c
Line
Count
Source (jump to first uncovered line)
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
PRIntn _PR_InvalidInt(void)
53
0
{
54
0
    PR_NOT_REACHED("I/O method is invalid");
55
0
    PR_SetError(PR_INVALID_METHOD_ERROR, 0);
56
0
    return -1;
57
0
}  /* _PR_InvalidInt */
58
59
PRInt16 _PR_InvalidInt16(void)
60
0
{
61
0
    PR_NOT_REACHED("I/O method is invalid");
62
0
    PR_SetError(PR_INVALID_METHOD_ERROR, 0);
63
0
    return -1;
64
0
}  /* _PR_InvalidInt */
65
66
PRInt64 _PR_InvalidInt64(void)
67
0
{
68
0
    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
0
}  /* _PR_InvalidInt */
74
75
/*
76
 * An invalid method that returns PRStatus
77
 */
78
79
PRStatus _PR_InvalidStatus(void)
80
0
{
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
0
}  /* _PR_InvalidDesc */
85
86
/*
87
 * An invalid method that returns a pointer
88
 */
89
90
PRFileDesc *_PR_InvalidDesc(void)
91
0
{
92
0
    PR_NOT_REACHED("I/O method is invalid");
93
0
    PR_SetError(PR_INVALID_METHOD_ERROR, 0);
94
0
    return NULL;
95
0
}  /* _PR_InvalidDesc */
96
97
PR_IMPLEMENT(PRDescType) PR_GetDescType(PRFileDesc *file)
98
0
{
99
0
    return file->methods->file_type;
100
0
}
101
102
PR_IMPLEMENT(PRStatus) PR_Close(PRFileDesc *fd)
103
0
{
104
0
    return (fd->methods->close)(fd);
105
0
}
106
107
PR_IMPLEMENT(PRInt32) PR_Read(PRFileDesc *fd, void *buf, PRInt32 amount)
108
0
{
109
0
    return((fd->methods->read)(fd,buf,amount));
110
0
}
111
112
PR_IMPLEMENT(PRInt32) PR_Write(PRFileDesc *fd, const void *buf, PRInt32 amount)
113
0
{
114
0
    return((fd->methods->write)(fd,buf,amount));
115
0
}
116
117
PR_IMPLEMENT(PRInt32) PR_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence)
118
0
{
119
0
    return((fd->methods->seek)(fd, offset, whence));
120
0
}
121
122
PR_IMPLEMENT(PRInt64) PR_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence)
123
0
{
124
0
    return((fd->methods->seek64)(fd, offset, whence));
125
0
}
126
127
PR_IMPLEMENT(PRInt32) PR_Available(PRFileDesc *fd)
128
0
{
129
0
    return((fd->methods->available)(fd));
130
0
}
131
132
PR_IMPLEMENT(PRInt64) PR_Available64(PRFileDesc *fd)
133
0
{
134
0
    return((fd->methods->available64)(fd));
135
0
}
136
137
PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo(PRFileDesc *fd, PRFileInfo *info)
138
0
{
139
0
    return((fd->methods->fileInfo)(fd, info));
140
0
}
141
142
PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo64(PRFileDesc *fd, PRFileInfo64 *info)
143
0
{
144
0
    return((fd->methods->fileInfo64)(fd, info));
145
0
}
146
147
PR_IMPLEMENT(PRStatus) PR_Sync(PRFileDesc *fd)
148
0
{
149
0
    return((fd->methods->fsync)(fd));
150
0
}
151
152
PR_IMPLEMENT(PRStatus) PR_Connect(
153
    PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
154
0
{
155
0
    return((fd->methods->connect)(fd,addr,timeout));
156
0
}
157
158
PR_IMPLEMENT(PRStatus) PR_ConnectContinue(
159
    PRFileDesc *fd, PRInt16 out_flags)
160
0
{
161
0
    return((fd->methods->connectcontinue)(fd,out_flags));
162
0
}
163
164
PR_IMPLEMENT(PRFileDesc*) PR_Accept(PRFileDesc *fd, PRNetAddr *addr,
165
                                    PRIntervalTime timeout)
166
0
{
167
0
    return((fd->methods->accept)(fd,addr,timeout));
168
0
}
169
170
PR_IMPLEMENT(PRStatus) PR_Bind(PRFileDesc *fd, const PRNetAddr *addr)
171
0
{
172
0
    return((fd->methods->bind)(fd,addr));
173
0
}
174
175
PR_IMPLEMENT(PRStatus) PR_Shutdown(PRFileDesc *fd, PRShutdownHow how)
176
0
{
177
0
    return((fd->methods->shutdown)(fd,how));
178
0
}
179
180
PR_IMPLEMENT(PRStatus) PR_Listen(PRFileDesc *fd, PRIntn backlog)
181
0
{
182
0
    return((fd->methods->listen)(fd,backlog));
183
0
}
184
185
PR_IMPLEMENT(PRInt32) PR_Recv(PRFileDesc *fd, void *buf, PRInt32 amount,
186
                              PRIntn flags, PRIntervalTime timeout)
187
0
{
188
0
    return((fd->methods->recv)(fd,buf,amount,flags,timeout));
189
0
}
190
191
PR_IMPLEMENT(PRInt32) PR_Send(PRFileDesc *fd, const void *buf, PRInt32 amount,
192
                              PRIntn flags, PRIntervalTime timeout)
193
0
{
194
0
    return((fd->methods->send)(fd,buf,amount,flags,timeout));
195
0
}
196
197
PR_IMPLEMENT(PRInt32) PR_Writev(PRFileDesc *fd, const PRIOVec *iov,
198
                                PRInt32 iov_size, PRIntervalTime timeout)
199
0
{
200
0
    if (iov_size > PR_MAX_IOVECTOR_SIZE)
201
0
    {
202
0
        PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
203
0
        return -1;
204
0
    }
205
0
    return((fd->methods->writev)(fd,iov,iov_size,timeout));
206
0
}
207
208
PR_IMPLEMENT(PRInt32) PR_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
209
                                  PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
210
0
{
211
0
    return((fd->methods->recvfrom)(fd,buf,amount,flags,addr,timeout));
212
0
}
213
214
PR_IMPLEMENT(PRInt32) PR_SendTo(
215
    PRFileDesc *fd, const void *buf, PRInt32 amount,
216
    PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
217
0
{
218
0
    return((fd->methods->sendto)(fd,buf,amount,flags,addr,timeout));
219
0
}
220
221
PR_IMPLEMENT(PRInt32) PR_TransmitFile(
222
    PRFileDesc *sd, PRFileDesc *fd, const void *hdr, PRInt32 hlen,
223
    PRTransmitFileFlags flags, PRIntervalTime timeout)
224
0
{
225
0
    return((sd->methods->transmitfile)(sd,fd,hdr,hlen,flags,timeout));
226
0
}
227
228
PR_IMPLEMENT(PRInt32) PR_AcceptRead(
229
    PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
230
    void *buf, PRInt32 amount, PRIntervalTime timeout)
231
0
{
232
0
    return((sd->methods->acceptread)(sd, nd, raddr, buf, amount,timeout));
233
0
}
234
235
PR_IMPLEMENT(PRStatus) PR_GetSockName(PRFileDesc *fd, PRNetAddr *addr)
236
0
{
237
0
    return((fd->methods->getsockname)(fd,addr));
238
0
}
239
240
PR_IMPLEMENT(PRStatus) PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
241
0
{
242
0
    return((fd->methods->getpeername)(fd,addr));
243
0
}
244
245
PR_IMPLEMENT(PRStatus) PR_GetSocketOption(
246
    PRFileDesc *fd, PRSocketOptionData *data)
247
0
{
248
0
    return((fd->methods->getsocketoption)(fd, data));
249
0
}
250
251
PR_IMPLEMENT(PRStatus) PR_SetSocketOption(
252
    PRFileDesc *fd, const PRSocketOptionData *data)
253
0
{
254
0
    return((fd->methods->setsocketoption)(fd, data));
255
0
}
256
257
PR_IMPLEMENT(PRInt32) PR_SendFile(
258
    PRFileDesc *sd, PRSendFileData *sfd,
259
    PRTransmitFileFlags flags, PRIntervalTime timeout)
260
0
{
261
0
    return((sd->methods->sendfile)(sd,sfd,flags,timeout));
262
0
}
263
264
PR_IMPLEMENT(PRInt32) PR_EmulateAcceptRead(
265
    PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
266
    void *buf, PRInt32 amount, PRIntervalTime timeout)
267
0
{
268
0
    PRInt32 rv = -1;
269
0
    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) {
278
0
        return rv;
279
0
    }
280
281
0
    rv = PR_Recv(accepted, buf, amount, 0, timeout);
282
0
    if (rv >= 0)
283
0
    {
284
        /* copy the new info out where caller can see it */
285
0
#define AMASK ((PRPtrdiff)7)  /* mask for alignment of PRNetAddr */
286
0
        PRPtrdiff aligned = (PRPtrdiff)buf + amount + AMASK;
287
0
        *raddr = (PRNetAddr*)(aligned & ~AMASK);
288
0
        memcpy(*raddr, &remote, PR_NETADDR_SIZE(&remote));
289
0
        *nd = accepted;
290
0
        return rv;
291
0
    }
292
293
0
    PR_Close(accepted);
294
0
    return rv;
295
0
}
296
297
/*
298
 * PR_EmulateSendFile
299
 *
300
 *    Send file sfd->fd across socket sd. If header/trailer are specified
301
 *    they are sent before and after the file, respectively.
302
 *
303
 *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
304
 *
305
 *    return number of bytes sent or -1 on error
306
 *
307
 */
308
309
#if defined(XP_UNIX) || defined(WIN32)
310
311
/*
312
 * An implementation based on memory-mapped files
313
 */
314
315
#define SENDFILE_MMAP_CHUNK (256 * 1024)
316
317
PR_IMPLEMENT(PRInt32) PR_EmulateSendFile(
318
    PRFileDesc *sd, PRSendFileData *sfd,
319
    PRTransmitFileFlags flags, PRIntervalTime timeout)
320
0
{
321
0
    PRInt32 rv, count = 0;
322
0
    PRInt32 len, file_bytes, index = 0;
323
0
    PRFileInfo info;
324
0
    PRIOVec iov[3];
325
0
    PRFileMap *mapHandle = NULL;
326
0
    void *addr = (void*)0; /* initialized to some arbitrary value. Keeps compiler warnings down. */
327
0
    PRUint32 file_mmap_offset, alignment;
328
0
    PRInt64 zero64;
329
0
    PROffset64 file_mmap_offset64;
330
0
    PRUint32 addr_offset, mmap_len;
331
332
    /* Get file size */
333
0
    if (PR_SUCCESS != PR_GetOpenFileInfo(sfd->fd, &info)) {
334
0
        count = -1;
335
0
        goto done;
336
0
    }
337
0
    if (sfd->file_nbytes &&
338
0
        (info.size < (sfd->file_offset + sfd->file_nbytes))) {
339
        /*
340
         * there are fewer bytes in file to send than specified
341
         */
342
0
        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
343
0
        count = -1;
344
0
        goto done;
345
0
    }
346
0
    if (sfd->file_nbytes) {
347
0
        file_bytes = sfd->file_nbytes;
348
0
    }
349
0
    else {
350
0
        file_bytes = info.size - sfd->file_offset;
351
0
    }
352
353
0
    alignment = PR_GetMemMapAlignment();
354
355
    /* number of initial bytes to skip in mmap'd segment */
356
0
    addr_offset = sfd->file_offset % alignment;
357
358
    /* find previous mmap alignment boundary */
359
0
    file_mmap_offset = sfd->file_offset - addr_offset;
360
361
    /*
362
     * If the file is large, mmap and send the file in chunks so as
363
     * to not consume too much virtual address space
364
     */
365
0
    mmap_len = PR_MIN(file_bytes + addr_offset, SENDFILE_MMAP_CHUNK);
366
0
    len = mmap_len - addr_offset;
367
368
    /*
369
     * Map in (part of) file. Take care of zero-length files.
370
     */
371
0
    if (len) {
372
0
        LL_I2L(zero64, 0);
373
0
        mapHandle = PR_CreateFileMap(sfd->fd, zero64, PR_PROT_READONLY);
374
0
        if (!mapHandle) {
375
0
            count = -1;
376
0
            goto done;
377
0
        }
378
0
        LL_I2L(file_mmap_offset64, file_mmap_offset);
379
0
        addr = PR_MemMap(mapHandle, file_mmap_offset64, mmap_len);
380
0
        if (!addr) {
381
0
            count = -1;
382
0
            goto done;
383
0
        }
384
0
    }
385
    /*
386
     * send headers first, followed by the file
387
     */
388
0
    if (sfd->hlen) {
389
0
        iov[index].iov_base = (char *) sfd->header;
390
0
        iov[index].iov_len = sfd->hlen;
391
0
        index++;
392
0
    }
393
0
    if (len) {
394
0
        iov[index].iov_base = (char*)addr + addr_offset;
395
0
        iov[index].iov_len = len;
396
0
        index++;
397
0
    }
398
0
    if ((file_bytes == len) && (sfd->tlen)) {
399
        /*
400
         * all file data is mapped in; send the trailer too
401
         */
402
0
        iov[index].iov_base = (char *) sfd->trailer;
403
0
        iov[index].iov_len = sfd->tlen;
404
0
        index++;
405
0
    }
406
0
    rv = PR_Writev(sd, iov, index, timeout);
407
0
    if (len) {
408
0
        PR_MemUnmap(addr, mmap_len);
409
0
    }
410
0
    if (rv < 0) {
411
0
        count = -1;
412
0
        goto done;
413
0
    }
414
415
0
    PR_ASSERT(rv == sfd->hlen + len + ((len == file_bytes) ? sfd->tlen : 0));
416
417
0
    file_bytes -= len;
418
0
    count += rv;
419
0
    if (!file_bytes) {  /* header, file and trailer are sent */
420
0
        goto done;
421
0
    }
422
423
    /*
424
     * send remaining bytes of the file, if any
425
     */
426
0
    len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
427
0
    while (len > 0) {
428
        /*
429
         * Map in (part of) file
430
         */
431
0
        file_mmap_offset = sfd->file_offset + count - sfd->hlen;
432
0
        PR_ASSERT((file_mmap_offset % alignment) == 0);
433
434
0
        LL_I2L(file_mmap_offset64, file_mmap_offset);
435
0
        addr = PR_MemMap(mapHandle, file_mmap_offset64, len);
436
0
        if (!addr) {
437
0
            count = -1;
438
0
            goto done;
439
0
        }
440
0
        rv = PR_Send(sd, addr, len, 0, timeout);
441
0
        PR_MemUnmap(addr, len);
442
0
        if (rv < 0) {
443
0
            count = -1;
444
0
            goto done;
445
0
        }
446
447
0
        PR_ASSERT(rv == len);
448
0
        file_bytes -= rv;
449
0
        count += rv;
450
0
        len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
451
0
    }
452
0
    PR_ASSERT(0 == file_bytes);
453
0
    if (sfd->tlen) {
454
0
        rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
455
0
        if (rv >= 0) {
456
0
            PR_ASSERT(rv == sfd->tlen);
457
0
            count += rv;
458
0
        } else {
459
0
            count = -1;
460
0
        }
461
0
    }
462
0
done:
463
0
    if (mapHandle) {
464
0
        PR_CloseFileMap(mapHandle);
465
0
    }
466
0
    if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) {
467
0
        PR_Close(sd);
468
0
    }
469
0
    return count;
470
0
}
471
472
#else
473
474
PR_IMPLEMENT(PRInt32) PR_EmulateSendFile(
475
    PRFileDesc *sd, PRSendFileData *sfd,
476
    PRTransmitFileFlags flags, PRIntervalTime timeout)
477
{
478
    PRInt32 rv, count = 0;
479
    PRInt32 rlen;
480
    const void * buffer;
481
    PRInt32 buflen;
482
    PRInt32 sendbytes, readbytes;
483
    char *buf;
484
485
#define _SENDFILE_BUFSIZE   (16 * 1024)
486
487
    buf = (char*)PR_MALLOC(_SENDFILE_BUFSIZE);
488
    if (buf == NULL) {
489
        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
490
        return -1;
491
    }
492
493
    /*
494
     * send header first
495
     */
496
    buflen = sfd->hlen;
497
    buffer = sfd->header;
498
    while (buflen) {
499
        rv = PR_Send(sd, buffer, buflen, 0, timeout);
500
        if (rv < 0) {
501
            /* PR_Send() has invoked PR_SetError(). */
502
            rv = -1;
503
            goto done;
504
        } else {
505
            count += rv;
506
            buffer = (const void*) ((const char*)buffer + rv);
507
            buflen -= rv;
508
        }
509
    }
510
511
    /*
512
     * send file next
513
     */
514
    if (PR_Seek(sfd->fd, sfd->file_offset, PR_SEEK_SET) < 0) {
515
        rv = -1;
516
        goto done;
517
    }
518
    sendbytes = sfd->file_nbytes;
519
    if (sendbytes == 0) {
520
        /* send entire file */
521
        while ((rlen = PR_Read(sfd->fd, buf, _SENDFILE_BUFSIZE)) > 0) {
522
            while (rlen) {
523
                char *bufptr = buf;
524
525
                rv =  PR_Send(sd, bufptr, rlen, 0, timeout);
526
                if (rv < 0) {
527
                    /* PR_Send() has invoked PR_SetError(). */
528
                    rv = -1;
529
                    goto done;
530
                } else {
531
                    count += rv;
532
                    bufptr = ((char*)bufptr + rv);
533
                    rlen -= rv;
534
                }
535
            }
536
        }
537
        if (rlen < 0) {
538
            /* PR_Read() has invoked PR_SetError(). */
539
            rv = -1;
540
            goto done;
541
        }
542
    } else {
543
        readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE);
544
        while (readbytes && ((rlen = PR_Read(sfd->fd, buf, readbytes)) > 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
                    sendbytes -= rv;
556
                    bufptr = ((char*)bufptr + rv);
557
                    rlen -= rv;
558
                }
559
            }
560
            readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE);
561
        }
562
        if (rlen < 0) {
563
            /* PR_Read() has invoked PR_SetError(). */
564
            rv = -1;
565
            goto done;
566
        } else if (sendbytes != 0) {
567
            /*
568
             * there are fewer bytes in file to send than specified
569
             */
570
            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
571
            rv = -1;
572
            goto done;
573
        }
574
    }
575
576
    /*
577
     * send trailer last
578
     */
579
    buflen = sfd->tlen;
580
    buffer = sfd->trailer;
581
    while (buflen) {
582
        rv =  PR_Send(sd, buffer, buflen, 0, timeout);
583
        if (rv < 0) {
584
            /* PR_Send() has invoked PR_SetError(). */
585
            rv = -1;
586
            goto done;
587
        } else {
588
            count += rv;
589
            buffer = (const void*) ((const char*)buffer + rv);
590
            buflen -= rv;
591
        }
592
    }
593
    rv = count;
594
595
done:
596
    if (buf) {
597
        PR_DELETE(buf);
598
    }
599
    if ((rv >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) {
600
        PR_Close(sd);
601
    }
602
    return rv;
603
}
604
605
#endif
606
607
/* priometh.c */