~ubuntu-branches/ubuntu/precise/libfcgi/precise-security

« back to all changes in this revision

Viewing changes to .pc/poll/libfcgi/os_unix.c

  • Committer: Package Import Robot
  • Author(s): Joe Damato
  • Date: 2015-02-05 16:28:53 UTC
  • Revision ID: package-import@ubuntu.com-20150205162853-j2vhdqv0y408n493
Tags: 2.4.0-8.1ubuntu0.1
Applying patch to swap select with poll to handle more than 1024
connections and avoid data corruption or a segfault. (LP: #1418778).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * os_unix.c --
 
3
 *
 
4
 *      Description of file.
 
5
 *
 
6
 *
 
7
 *  Copyright (c) 1995 Open Market, Inc.
 
8
 *  All rights reserved.
 
9
 *
 
10
 *  This file contains proprietary and confidential information and
 
11
 *  remains the unpublished property of Open Market, Inc. Use,
 
12
 *  disclosure, or reproduction is prohibited except as permitted by
 
13
 *  express written license agreement with Open Market, Inc.
 
14
 *
 
15
 *  Bill Snapper
 
16
 *  snapper@openmarket.com
 
17
 */
 
18
 
 
19
#ifndef lint
 
20
static const char rcsid[] = "$Id: os_unix.c,v 1.37 2002/03/05 19:14:49 robs Exp $";
 
21
#endif /* not lint */
 
22
 
 
23
#include "fcgi_config.h"
 
24
 
 
25
#include <sys/types.h>
 
26
 
 
27
#ifdef HAVE_NETINET_IN_H
 
28
#include <netinet/in.h>
 
29
#endif
 
30
 
 
31
#include <arpa/inet.h>
 
32
#include <assert.h>
 
33
#include <errno.h>
 
34
#include <fcntl.h>      /* for fcntl */
 
35
#include <math.h>
 
36
#include <memory.h>     /* for memchr() */
 
37
#include <netinet/tcp.h>
 
38
#include <stdarg.h>
 
39
#include <stdio.h>
 
40
#include <stdlib.h>
 
41
#include <string.h>
 
42
#include <sys/time.h>
 
43
#include <sys/un.h>
 
44
#include <signal.h>
 
45
 
 
46
#ifdef HAVE_NETDB_H
 
47
#include <netdb.h>
 
48
#endif
 
49
 
 
50
#ifdef HAVE_SYS_SOCKET_H
 
51
#include <sys/socket.h> /* for getpeername */
 
52
#endif
 
53
 
 
54
#ifdef HAVE_UNISTD_H
 
55
#include <unistd.h>
 
56
#endif
 
57
 
 
58
#include "fastcgi.h"
 
59
#include "fcgimisc.h"
 
60
#include "fcgios.h"
 
61
 
 
62
#ifndef INADDR_NONE
 
63
#define INADDR_NONE ((unsigned long) -1)
 
64
#endif
 
65
 
 
66
/*
 
67
 * This structure holds an entry for each oustanding async I/O operation.
 
68
 */
 
69
typedef struct {
 
70
    OS_AsyncProc procPtr;           /* callout completion procedure */
 
71
    ClientData clientData;          /* caller private data */
 
72
    int fd;
 
73
    int len;
 
74
    int offset;
 
75
    void *buf;
 
76
    int inUse;
 
77
} AioInfo;
 
78
 
 
79
/*
 
80
 * Entries in the async I/O table are allocated 2 per file descriptor.
 
81
 *
 
82
 * Read Entry Index  = fd * 2
 
83
 * Write Entry Index = (fd * 2) + 1
 
84
 */
 
85
#define AIO_RD_IX(fd) (fd * 2)
 
86
#define AIO_WR_IX(fd) ((fd * 2) + 1)
 
87
 
 
88
static int asyncIoInUse = FALSE;
 
89
static int asyncIoTableSize = 16;
 
90
static AioInfo *asyncIoTable = NULL;
 
91
 
 
92
static int libInitialized = FALSE;
 
93
 
 
94
static fd_set readFdSet;
 
95
static fd_set writeFdSet;
 
96
 
 
97
static fd_set readFdSetPost;
 
98
static int numRdPosted = 0;
 
99
static fd_set writeFdSetPost;
 
100
static int numWrPosted = 0;
 
101
static int volatile maxFd = -1;
 
102
 
 
103
static int shutdownPending = FALSE;
 
104
static int shutdownNow = FALSE;
 
105
 
 
106
void OS_ShutdownPending()
 
107
{
 
108
    shutdownPending = TRUE;
 
109
}
 
110
 
 
111
static void OS_Sigusr1Handler(int signo)
 
112
{
 
113
    OS_ShutdownPending();
 
114
}
 
115
 
 
116
static void OS_SigpipeHandler(int signo)
 
117
{
 
118
    ;
 
119
}
 
120
 
 
121
static void installSignalHandler(int signo, const struct sigaction * act, int force)
 
122
{
 
123
    struct sigaction sa;
 
124
 
 
125
    sigaction(signo, NULL, &sa);
 
126
 
 
127
    if (force || sa.sa_handler == SIG_DFL) 
 
128
    {
 
129
        sigaction(signo, act, NULL);
 
130
    }
 
131
}
 
132
 
 
133
static void OS_InstallSignalHandlers(int force)
 
134
{
 
135
    struct sigaction sa;
 
136
 
 
137
    sigemptyset(&sa.sa_mask);
 
138
    sa.sa_flags = 0;
 
139
 
 
140
    sa.sa_handler = OS_SigpipeHandler;
 
141
    installSignalHandler(SIGPIPE, &sa, force);
 
142
 
 
143
    sa.sa_handler = OS_Sigusr1Handler;
 
144
    installSignalHandler(SIGUSR1, &sa, force);
 
145
}
 
146
 
 
147
/*
 
148
 *--------------------------------------------------------------
 
149
 *
 
150
 * OS_LibInit --
 
151
 *
 
152
 *      Set up the OS library for use.
 
153
 *
 
154
 *      NOTE: This function is really only needed for application
 
155
 *            asynchronous I/O.  It will most likely change in the
 
156
 *            future to setup the multi-threaded environment.
 
157
 *
 
158
 * Results:
 
159
 *      Returns 0 if success, -1 if not.
 
160
 *
 
161
 * Side effects:
 
162
 *      Async I/O table allocated and initialized.
 
163
 *
 
164
 *--------------------------------------------------------------
 
165
 */
 
166
int OS_LibInit(int stdioFds[3])
 
167
{
 
168
    if(libInitialized)
 
169
        return 0;
 
170
 
 
171
    asyncIoTable = (AioInfo *)malloc(asyncIoTableSize * sizeof(AioInfo));
 
172
    if(asyncIoTable == NULL) {
 
173
        errno = ENOMEM;
 
174
        return -1;
 
175
    }
 
176
    memset((char *) asyncIoTable, 0,
 
177
           asyncIoTableSize * sizeof(AioInfo));
 
178
 
 
179
    FD_ZERO(&readFdSet);
 
180
    FD_ZERO(&writeFdSet);
 
181
    FD_ZERO(&readFdSetPost);
 
182
    FD_ZERO(&writeFdSetPost);
 
183
 
 
184
    OS_InstallSignalHandlers(FALSE);
 
185
 
 
186
    libInitialized = TRUE;
 
187
 
 
188
    return 0;
 
189
}
 
190
 
 
191
/*
 
192
 *--------------------------------------------------------------
 
193
 *
 
194
 * OS_LibShutdown --
 
195
 *
 
196
 *      Shutdown the OS library.
 
197
 *
 
198
 * Results:
 
199
 *      None.
 
200
 *
 
201
 * Side effects:
 
202
 *      Memory freed, fds closed.
 
203
 *
 
204
 *--------------------------------------------------------------
 
205
 */
 
206
void OS_LibShutdown()
 
207
{
 
208
    if(!libInitialized)
 
209
        return;
 
210
 
 
211
    free(asyncIoTable);
 
212
    asyncIoTable = NULL;
 
213
    libInitialized = FALSE;
 
214
    return;
 
215
}
 
216
 
 
217
/*
 
218
 *----------------------------------------------------------------------
 
219
 *
 
220
 * OS_BuildSockAddrUn --
 
221
 *
 
222
 *      Using the pathname bindPath, fill in the sockaddr_un structure
 
223
 *      *servAddrPtr and the length of this structure *servAddrLen.
 
224
 *
 
225
 *      The format of the sockaddr_un structure changed incompatibly in
 
226
 *      4.3BSD Reno.  Digital UNIX supports both formats, other systems
 
227
 *      support one or the other.
 
228
 *
 
229
 * Results:
 
230
 *      0 for normal return, -1 for failure (bindPath too long).
 
231
 *
 
232
 *----------------------------------------------------------------------
 
233
 */
 
234
 
 
235
static int OS_BuildSockAddrUn(const char *bindPath,
 
236
                              struct sockaddr_un *servAddrPtr,
 
237
                              int *servAddrLen)
 
238
{
 
239
    int bindPathLen = strlen(bindPath);
 
240
 
 
241
#ifdef HAVE_SOCKADDR_UN_SUN_LEN /* 4.3BSD Reno and later: BSDI, DEC */
 
242
    if(bindPathLen >= sizeof(servAddrPtr->sun_path)) {
 
243
        return -1;
 
244
    }
 
245
#else                           /* 4.3 BSD Tahoe: Solaris, HPUX, DEC, ... */
 
246
    if(bindPathLen > sizeof(servAddrPtr->sun_path)) {
 
247
        return -1;
 
248
    }
 
249
#endif
 
250
    memset((char *) servAddrPtr, 0, sizeof(*servAddrPtr));
 
251
    servAddrPtr->sun_family = AF_UNIX;
 
252
    memcpy(servAddrPtr->sun_path, bindPath, bindPathLen);
 
253
#ifdef HAVE_SOCKADDR_UN_SUN_LEN /* 4.3BSD Reno and later: BSDI, DEC */
 
254
    *servAddrLen = sizeof(servAddrPtr->sun_len)
 
255
            + sizeof(servAddrPtr->sun_family)
 
256
            + bindPathLen + 1;
 
257
    servAddrPtr->sun_len = *servAddrLen;
 
258
#else                           /* 4.3 BSD Tahoe: Solaris, HPUX, DEC, ... */
 
259
    *servAddrLen = sizeof(servAddrPtr->sun_family) + bindPathLen;
 
260
#endif
 
261
    return 0;
 
262
}
 
263
union SockAddrUnion {
 
264
    struct  sockaddr_un unixVariant;
 
265
    struct  sockaddr_in inetVariant;
 
266
};
 
267
 
 
268
/*
 
269
 * OS_CreateLocalIpcFd --
 
270
 *
 
271
 *   This procedure is responsible for creating the listener socket
 
272
 *   on Unix for local process communication.  It will create a
 
273
 *   domain socket or a TCP/IP socket bound to "localhost" and return
 
274
 *   a file descriptor to it to the caller.
 
275
 *
 
276
 * Results:
 
277
 *      Listener socket created.  This call returns either a valid
 
278
 *      file descriptor or -1 on error.
 
279
 *
 
280
 * Side effects:
 
281
 *      None.
 
282
 *
 
283
 *----------------------------------------------------------------------
 
284
 */
 
285
int OS_CreateLocalIpcFd(const char *bindPath, int backlog)
 
286
{
 
287
    int listenSock, servLen;
 
288
    union   SockAddrUnion sa;  
 
289
    int     tcp = FALSE;
 
290
    unsigned long tcp_ia = 0;
 
291
    char    *tp;
 
292
    short   port = 0;
 
293
    char    host[MAXPATHLEN];
 
294
 
 
295
    strcpy(host, bindPath);
 
296
    if((tp = strchr(host, ':')) != 0) {
 
297
        *tp++ = 0;
 
298
        if((port = atoi(tp)) == 0) {
 
299
            *--tp = ':';
 
300
         } else {
 
301
            tcp = TRUE;
 
302
         }
 
303
    }
 
304
    if(tcp) {
 
305
      if (!*host || !strcmp(host,"*")) {
 
306
        tcp_ia = htonl(INADDR_ANY);
 
307
      } else {
 
308
        tcp_ia = inet_addr(host);
 
309
        if (tcp_ia == INADDR_NONE) {
 
310
          struct hostent * hep;
 
311
          hep = gethostbyname(host);
 
312
          if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
 
313
            fprintf(stderr, "Cannot resolve host name %s -- exiting!\n", host);
 
314
            exit(1);
 
315
          }
 
316
          if (hep->h_addr_list[1]) {
 
317
            fprintf(stderr, "Host %s has multiple addresses ---\n", host);
 
318
            fprintf(stderr, "you must choose one explicitly!!!\n");
 
319
            exit(1);
 
320
          }
 
321
          tcp_ia = ((struct in_addr *) (hep->h_addr))->s_addr;
 
322
        }
 
323
      }
 
324
    }
 
325
 
 
326
    if(tcp) {
 
327
        listenSock = socket(AF_INET, SOCK_STREAM, 0);
 
328
        if(listenSock >= 0) {
 
329
            int flag = 1;
 
330
            if(setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR,
 
331
                          (char *) &flag, sizeof(flag)) < 0) {
 
332
                fprintf(stderr, "Can't set SO_REUSEADDR.\n");
 
333
                exit(1001);
 
334
            }
 
335
        }
 
336
    } else {
 
337
        listenSock = socket(AF_UNIX, SOCK_STREAM, 0);
 
338
    }
 
339
    if(listenSock < 0) {
 
340
        return -1;
 
341
    }
 
342
 
 
343
    /*
 
344
     * Bind the listening socket.
 
345
     */
 
346
    if(tcp) {
 
347
        memset((char *) &sa.inetVariant, 0, sizeof(sa.inetVariant));
 
348
        sa.inetVariant.sin_family = AF_INET;
 
349
        sa.inetVariant.sin_addr.s_addr = tcp_ia;
 
350
        sa.inetVariant.sin_port = htons(port);
 
351
        servLen = sizeof(sa.inetVariant);
 
352
    } else {
 
353
        unlink(bindPath);
 
354
        if(OS_BuildSockAddrUn(bindPath, &sa.unixVariant, &servLen)) {
 
355
            fprintf(stderr, "Listening socket's path name is too long.\n");
 
356
            exit(1000);
 
357
        }
 
358
    }
 
359
    if(bind(listenSock, (struct sockaddr *) &sa.unixVariant, servLen) < 0
 
360
       || listen(listenSock, backlog) < 0) {
 
361
        perror("bind/listen");
 
362
        exit(errno);
 
363
    }
 
364
 
 
365
    return listenSock;
 
366
}
 
367
 
 
368
/*
 
369
 *----------------------------------------------------------------------
 
370
 *
 
371
 * OS_FcgiConnect --
 
372
 *
 
373
 *      Create the socket and connect to the remote application if
 
374
 *      possible.
 
375
 *
 
376
 *      This was lifted from the cgi-fcgi application and was abstracted
 
377
 *      out because Windows NT does not have a domain socket and must
 
378
 *      use a named pipe which has a different API altogether.
 
379
 *
 
380
 * Results:
 
381
 *      -1 if fail or a valid file descriptor if connection succeeds.
 
382
 *
 
383
 * Side effects:
 
384
 *      Remote connection established.
 
385
 *
 
386
 *----------------------------------------------------------------------
 
387
 */
 
388
int OS_FcgiConnect(char *bindPath)
 
389
{
 
390
    union   SockAddrUnion sa;
 
391
    int servLen, resultSock;
 
392
    int connectStatus;
 
393
    char    *tp;
 
394
    char    host[MAXPATHLEN];
 
395
    short   port = 0;
 
396
    int     tcp = FALSE;
 
397
 
 
398
    strcpy(host, bindPath);
 
399
    if((tp = strchr(host, ':')) != 0) {
 
400
        *tp++ = 0;
 
401
        if((port = atoi(tp)) == 0) {
 
402
            *--tp = ':';
 
403
         } else {
 
404
            tcp = TRUE;
 
405
         }
 
406
    }
 
407
    if(tcp == TRUE) {
 
408
        struct  hostent *hp;
 
409
        if((hp = gethostbyname((*host ? host : "localhost"))) == NULL) {
 
410
            fprintf(stderr, "Unknown host: %s\n", bindPath);
 
411
            exit(1000);
 
412
        }
 
413
        sa.inetVariant.sin_family = AF_INET;
 
414
        memcpy(&sa.inetVariant.sin_addr, hp->h_addr, hp->h_length);
 
415
        sa.inetVariant.sin_port = htons(port);
 
416
        servLen = sizeof(sa.inetVariant);
 
417
        resultSock = socket(AF_INET, SOCK_STREAM, 0);
 
418
    } else {
 
419
        if(OS_BuildSockAddrUn(bindPath, &sa.unixVariant, &servLen)) {
 
420
            fprintf(stderr, "Listening socket's path name is too long.\n");
 
421
            exit(1000);
 
422
        }
 
423
        resultSock = socket(AF_UNIX, SOCK_STREAM, 0);
 
424
    }
 
425
 
 
426
    ASSERT(resultSock >= 0);
 
427
    connectStatus = connect(resultSock, (struct sockaddr *) &sa.unixVariant,
 
428
                             servLen);
 
429
    if(connectStatus >= 0) {
 
430
        return resultSock;
 
431
    } else {
 
432
        /*
 
433
         * Most likely (errno == ENOENT || errno == ECONNREFUSED)
 
434
         * and no FCGI application server is running.
 
435
         */
 
436
        close(resultSock);
 
437
        return -1;
 
438
    }
 
439
}
 
440
 
 
441
/*
 
442
 *--------------------------------------------------------------
 
443
 *
 
444
 * OS_Read --
 
445
 *
 
446
 *      Pass through to the unix read function.
 
447
 *
 
448
 * Results:
 
449
 *      Returns number of byes read, 0, or -1 failure: errno
 
450
 *      contains actual error.
 
451
 *
 
452
 * Side effects:
 
453
 *      None.
 
454
 *
 
455
 *--------------------------------------------------------------
 
456
 */
 
457
int OS_Read(int fd, char * buf, size_t len)
 
458
{
 
459
    if (shutdownNow) return -1;
 
460
    return(read(fd, buf, len));
 
461
}
 
462
 
 
463
/*
 
464
 *--------------------------------------------------------------
 
465
 *
 
466
 * OS_Write --
 
467
 *
 
468
 *      Pass through to unix write function.
 
469
 *
 
470
 * Results:
 
471
 *      Returns number of byes read, 0, or -1 failure: errno
 
472
 *      contains actual error.
 
473
 *
 
474
 * Side effects:
 
475
 *      none.
 
476
 *
 
477
 *--------------------------------------------------------------
 
478
 */
 
479
int OS_Write(int fd, char * buf, size_t len)
 
480
{
 
481
    if (shutdownNow) return -1;
 
482
    return(write(fd, buf, len));
 
483
}
 
484
 
 
485
/*
 
486
 *----------------------------------------------------------------------
 
487
 *
 
488
 * OS_SpawnChild --
 
489
 *
 
490
 *      Spawns a new FastCGI listener process.
 
491
 *
 
492
 * Results:
 
493
 *      0 if success, -1 if error.
 
494
 *
 
495
 * Side effects:
 
496
 *      Child process spawned.
 
497
 *
 
498
 *----------------------------------------------------------------------
 
499
 */
 
500
int OS_SpawnChild(char *appPath, int listenFd)
 
501
{
 
502
    int forkResult;
 
503
 
 
504
    forkResult = fork();
 
505
    if(forkResult < 0) {
 
506
        exit(errno);
 
507
    }
 
508
 
 
509
    if(forkResult == 0) {
 
510
        /*
 
511
         * Close STDIN unconditionally.  It's used by the parent
 
512
         * process for CGI communication.  The FastCGI applciation
 
513
         * will be replacing this with the FastCGI listenFd IF
 
514
         * STDIN_FILENO is the same as FCGI_LISTENSOCK_FILENO
 
515
         * (which it is on Unix).  Regardless, STDIN, STDOUT, and
 
516
         * STDERR will be closed as the FastCGI process uses a
 
517
         * multiplexed socket in their place.
 
518
         */
 
519
        close(STDIN_FILENO);
 
520
 
 
521
        /*
 
522
         * If the listenFd is already the value of FCGI_LISTENSOCK_FILENO
 
523
         * we're set.  If not, change it so the child knows where to
 
524
         * get the listen socket from.
 
525
         */
 
526
        if(listenFd != FCGI_LISTENSOCK_FILENO) {
 
527
            dup2(listenFd, FCGI_LISTENSOCK_FILENO);
 
528
            close(listenFd);
 
529
        }
 
530
 
 
531
        close(STDOUT_FILENO);
 
532
        close(STDERR_FILENO);
 
533
 
 
534
        /*
 
535
         * We're a child.  Exec the application.
 
536
         *
 
537
         * XXX: entire environment passes through
 
538
         */
 
539
        execl(appPath, appPath, NULL);
 
540
        /*
 
541
         * XXX: Can't do this as we've already closed STDERR!!!
 
542
         *
 
543
         * perror("exec");
 
544
         */
 
545
        exit(errno);
 
546
    }
 
547
    return 0;
 
548
}
 
549
 
 
550
/*
 
551
 *--------------------------------------------------------------
 
552
 *
 
553
 * OS_AsyncReadStdin --
 
554
 *
 
555
 *      This initiates an asynchronous read on the standard
 
556
 *      input handle.
 
557
 *
 
558
 *      The abstraction is necessary because Windows NT does not
 
559
 *      have a clean way of "select"ing a file descriptor for
 
560
 *      I/O.
 
561
 *
 
562
 * Results:
 
563
 *      -1 if error, 0 otherwise.
 
564
 *
 
565
 * Side effects:
 
566
 *      Asynchronous bit is set in the readfd variable and
 
567
 *      request is enqueued.
 
568
 *
 
569
 *--------------------------------------------------------------
 
570
 */
 
571
int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr,
 
572
                      ClientData clientData)
 
573
{
 
574
    int index = AIO_RD_IX(STDIN_FILENO);
 
575
 
 
576
    asyncIoInUse = TRUE;
 
577
    ASSERT(asyncIoTable[index].inUse == 0);
 
578
    asyncIoTable[index].procPtr = procPtr;
 
579
    asyncIoTable[index].clientData = clientData;
 
580
    asyncIoTable[index].fd = STDIN_FILENO;
 
581
    asyncIoTable[index].len = len;
 
582
    asyncIoTable[index].offset = 0;
 
583
    asyncIoTable[index].buf = buf;
 
584
    asyncIoTable[index].inUse = 1;
 
585
    FD_SET(STDIN_FILENO, &readFdSet);
 
586
    if(STDIN_FILENO > maxFd)
 
587
        maxFd = STDIN_FILENO;
 
588
    return 0;
 
589
}
 
590
 
 
591
static void GrowAsyncTable(void)
 
592
{
 
593
    int oldTableSize = asyncIoTableSize;
 
594
 
 
595
    asyncIoTableSize = asyncIoTableSize * 2;
 
596
    asyncIoTable = (AioInfo *)realloc(asyncIoTable, asyncIoTableSize * sizeof(AioInfo));
 
597
    if(asyncIoTable == NULL) {
 
598
        errno = ENOMEM;
 
599
        exit(errno);
 
600
    }
 
601
    memset((char *) &asyncIoTable[oldTableSize], 0,
 
602
           oldTableSize * sizeof(AioInfo));
 
603
 
 
604
}
 
605
 
 
606
/*
 
607
 *--------------------------------------------------------------
 
608
 *
 
609
 * OS_AsyncRead --
 
610
 *
 
611
 *      This initiates an asynchronous read on the file
 
612
 *      handle which may be a socket or named pipe.
 
613
 *
 
614
 *      We also must save the ProcPtr and ClientData, so later
 
615
 *      when the io completes, we know who to call.
 
616
 *
 
617
 *      We don't look at any results here (the ReadFile may
 
618
 *      return data if it is cached) but do all completion
 
619
 *      processing in OS_Select when we get the io completion
 
620
 *      port done notifications.  Then we call the callback.
 
621
 *
 
622
 * Results:
 
623
 *      -1 if error, 0 otherwise.
 
624
 *
 
625
 * Side effects:
 
626
 *      Asynchronous I/O operation is queued for completion.
 
627
 *
 
628
 *--------------------------------------------------------------
 
629
 */
 
630
int OS_AsyncRead(int fd, int offset, void *buf, int len,
 
631
                 OS_AsyncProc procPtr, ClientData clientData)
 
632
{
 
633
    int index = AIO_RD_IX(fd);
 
634
 
 
635
    ASSERT(asyncIoTable != NULL);
 
636
    asyncIoInUse = TRUE;
 
637
 
 
638
    if(fd > maxFd)
 
639
        maxFd = fd;
 
640
 
 
641
    while (index >= asyncIoTableSize) {
 
642
        GrowAsyncTable();
 
643
    }
 
644
 
 
645
    ASSERT(asyncIoTable[index].inUse == 0);
 
646
    asyncIoTable[index].procPtr = procPtr;
 
647
    asyncIoTable[index].clientData = clientData;
 
648
    asyncIoTable[index].fd = fd;
 
649
    asyncIoTable[index].len = len;
 
650
    asyncIoTable[index].offset = offset;
 
651
    asyncIoTable[index].buf = buf;
 
652
    asyncIoTable[index].inUse = 1;
 
653
    FD_SET(fd, &readFdSet);
 
654
    return 0;
 
655
}
 
656
 
 
657
/*
 
658
 *--------------------------------------------------------------
 
659
 *
 
660
 * OS_AsyncWrite --
 
661
 *
 
662
 *      This initiates an asynchronous write on the "fake" file
 
663
 *      descriptor (which may be a file, socket, or named pipe).
 
664
 *      We also must save the ProcPtr and ClientData, so later
 
665
 *      when the io completes, we know who to call.
 
666
 *
 
667
 *      We don't look at any results here (the WriteFile generally
 
668
 *      completes immediately) but do all completion processing
 
669
 *      in OS_DoIo when we get the io completion port done
 
670
 *      notifications.  Then we call the callback.
 
671
 *
 
672
 * Results:
 
673
 *      -1 if error, 0 otherwise.
 
674
 *
 
675
 * Side effects:
 
676
 *      Asynchronous I/O operation is queued for completion.
 
677
 *
 
678
 *--------------------------------------------------------------
 
679
 */
 
680
int OS_AsyncWrite(int fd, int offset, void *buf, int len,
 
681
                  OS_AsyncProc procPtr, ClientData clientData)
 
682
{
 
683
    int index = AIO_WR_IX(fd);
 
684
 
 
685
    asyncIoInUse = TRUE;
 
686
 
 
687
    if(fd > maxFd)
 
688
        maxFd = fd;
 
689
 
 
690
    while (index >= asyncIoTableSize) {
 
691
        GrowAsyncTable();
 
692
    }
 
693
 
 
694
    ASSERT(asyncIoTable[index].inUse == 0);
 
695
    asyncIoTable[index].procPtr = procPtr;
 
696
    asyncIoTable[index].clientData = clientData;
 
697
    asyncIoTable[index].fd = fd;
 
698
    asyncIoTable[index].len = len;
 
699
    asyncIoTable[index].offset = offset;
 
700
    asyncIoTable[index].buf = buf;
 
701
    asyncIoTable[index].inUse = 1;
 
702
    FD_SET(fd, &writeFdSet);
 
703
    return 0;
 
704
}
 
705
 
 
706
/*
 
707
 *--------------------------------------------------------------
 
708
 *
 
709
 * OS_Close --
 
710
 *
 
711
 *      Closes the descriptor.  This is a pass through to the
 
712
 *      Unix close.
 
713
 *
 
714
 * Results:
 
715
 *      0 for success, -1 on failure
 
716
 *
 
717
 * Side effects:
 
718
 *      None.
 
719
 *
 
720
 *--------------------------------------------------------------
 
721
 */
 
722
int OS_Close(int fd)
 
723
{
 
724
    if (fd == -1)
 
725
        return 0;
 
726
 
 
727
    if (asyncIoInUse) {
 
728
        int index = AIO_RD_IX(fd);
 
729
 
 
730
        FD_CLR(fd, &readFdSet);
 
731
        FD_CLR(fd, &readFdSetPost);
 
732
        if (asyncIoTable[index].inUse != 0) {
 
733
            asyncIoTable[index].inUse = 0;
 
734
        }
 
735
 
 
736
        FD_CLR(fd, &writeFdSet);
 
737
        FD_CLR(fd, &writeFdSetPost);
 
738
        index = AIO_WR_IX(fd);
 
739
        if (asyncIoTable[index].inUse != 0) {
 
740
            asyncIoTable[index].inUse = 0;
 
741
        }
 
742
 
 
743
        if (maxFd == fd) {
 
744
            maxFd--;
 
745
        }
 
746
    }
 
747
 
 
748
    /*
 
749
     * shutdown() the send side and then read() from client until EOF
 
750
     * or a timeout expires.  This is done to minimize the potential
 
751
     * that a TCP RST will be sent by our TCP stack in response to 
 
752
     * receipt of additional data from the client.  The RST would
 
753
     * cause the client to discard potentially useful response data.
 
754
     */
 
755
 
 
756
    if (shutdown(fd, 1) == 0)
 
757
    {
 
758
        struct timeval tv;
 
759
        fd_set rfds;
 
760
        int rv;
 
761
        char trash[1024];
 
762
 
 
763
        FD_ZERO(&rfds);
 
764
 
 
765
        do 
 
766
        {
 
767
            FD_SET(fd, &rfds);
 
768
            tv.tv_sec = 2;
 
769
            tv.tv_usec = 0;
 
770
            rv = select(fd + 1, &rfds, NULL, NULL, &tv);
 
771
        }
 
772
        while (rv > 0 && read(fd, trash, sizeof(trash)) > 0);
 
773
    }
 
774
 
 
775
    return close(fd);
 
776
}
 
777
 
 
778
/*
 
779
 *--------------------------------------------------------------
 
780
 *
 
781
 * OS_CloseRead --
 
782
 *
 
783
 *      Cancel outstanding asynchronous reads and prevent subsequent
 
784
 *      reads from completing.
 
785
 *
 
786
 * Results:
 
787
 *      Socket or file is shutdown. Return values mimic Unix shutdown:
 
788
 *              0 success, -1 failure
 
789
 *
 
790
 *--------------------------------------------------------------
 
791
 */
 
792
int OS_CloseRead(int fd)
 
793
{
 
794
    if(asyncIoTable[AIO_RD_IX(fd)].inUse != 0) {
 
795
        asyncIoTable[AIO_RD_IX(fd)].inUse = 0;
 
796
        FD_CLR(fd, &readFdSet);
 
797
    }
 
798
 
 
799
    return shutdown(fd, 0);
 
800
}
 
801
 
 
802
/*
 
803
 *--------------------------------------------------------------
 
804
 *
 
805
 * OS_DoIo --
 
806
 *
 
807
 *      This function was formerly OS_Select.  It's purpose is
 
808
 *      to pull I/O completion events off the queue and dispatch
 
809
 *      them to the appropriate place.
 
810
 *
 
811
 * Results:
 
812
 *      Returns 0.
 
813
 *
 
814
 * Side effects:
 
815
 *      Handlers are called.
 
816
 *
 
817
 *--------------------------------------------------------------
 
818
 */
 
819
int OS_DoIo(struct timeval *tmo)
 
820
{
 
821
    int fd, len, selectStatus;
 
822
    OS_AsyncProc procPtr;
 
823
    ClientData clientData;
 
824
    AioInfo *aioPtr;
 
825
    fd_set readFdSetCpy;
 
826
    fd_set writeFdSetCpy;
 
827
 
 
828
    asyncIoInUse = TRUE;
 
829
    FD_ZERO(&readFdSetCpy);
 
830
    FD_ZERO(&writeFdSetCpy);
 
831
 
 
832
    for(fd = 0; fd <= maxFd; fd++) {
 
833
        if(FD_ISSET(fd, &readFdSet)) {
 
834
            FD_SET(fd, &readFdSetCpy);
 
835
        }
 
836
        if(FD_ISSET(fd, &writeFdSet)) {
 
837
            FD_SET(fd, &writeFdSetCpy);
 
838
        }
 
839
    }
 
840
 
 
841
    /*
 
842
     * If there were no completed events from a prior call, see if there's
 
843
     * any work to do.
 
844
     */
 
845
    if(numRdPosted == 0 && numWrPosted == 0) {
 
846
        selectStatus = select((maxFd+1), &readFdSetCpy, &writeFdSetCpy,
 
847
                              NULL, tmo);
 
848
        if(selectStatus < 0) {
 
849
            exit(errno);
 
850
        }
 
851
 
 
852
        for(fd = 0; fd <= maxFd; fd++) {
 
853
            /*
 
854
             * Build up a list of completed events.  We'll work off of
 
855
             * this list as opposed to looping through the read and write
 
856
             * fd sets since they can be affected by a callbacl routine.
 
857
             */
 
858
            if(FD_ISSET(fd, &readFdSetCpy)) {
 
859
                numRdPosted++;
 
860
                FD_SET(fd, &readFdSetPost);
 
861
                FD_CLR(fd, &readFdSet);
 
862
            }
 
863
 
 
864
            if(FD_ISSET(fd, &writeFdSetCpy)) {
 
865
                numWrPosted++;
 
866
                FD_SET(fd, &writeFdSetPost);
 
867
                FD_CLR(fd, &writeFdSet);
 
868
            }
 
869
        }
 
870
    }
 
871
 
 
872
    if(numRdPosted == 0 && numWrPosted == 0)
 
873
        return 0;
 
874
 
 
875
    for(fd = 0; fd <= maxFd; fd++) {
 
876
        /*
 
877
         * Do reads and dispatch callback.
 
878
         */
 
879
        if(FD_ISSET(fd, &readFdSetPost)
 
880
           && asyncIoTable[AIO_RD_IX(fd)].inUse) {
 
881
 
 
882
            numRdPosted--;
 
883
            FD_CLR(fd, &readFdSetPost);
 
884
            aioPtr = &asyncIoTable[AIO_RD_IX(fd)];
 
885
 
 
886
            len = read(aioPtr->fd, aioPtr->buf, aioPtr->len);
 
887
 
 
888
            procPtr = aioPtr->procPtr;
 
889
            aioPtr->procPtr = NULL;
 
890
            clientData = aioPtr->clientData;
 
891
            aioPtr->inUse = 0;
 
892
 
 
893
            (*procPtr)(clientData, len);
 
894
        }
 
895
 
 
896
        /*
 
897
         * Do writes and dispatch callback.
 
898
         */
 
899
        if(FD_ISSET(fd, &writeFdSetPost) &&
 
900
           asyncIoTable[AIO_WR_IX(fd)].inUse) {
 
901
 
 
902
            numWrPosted--;
 
903
            FD_CLR(fd, &writeFdSetPost);
 
904
            aioPtr = &asyncIoTable[AIO_WR_IX(fd)];
 
905
 
 
906
            len = write(aioPtr->fd, aioPtr->buf, aioPtr->len);
 
907
 
 
908
            procPtr = aioPtr->procPtr;
 
909
            aioPtr->procPtr = NULL;
 
910
            clientData = aioPtr->clientData;
 
911
            aioPtr->inUse = 0;
 
912
            (*procPtr)(clientData, len);
 
913
        }
 
914
    }
 
915
    return 0;
 
916
}
 
917
 
 
918
/* 
 
919
 * Not all systems have strdup().  
 
920
 * @@@ autoconf should determine whether or not this is needed, but for now..
 
921
 */
 
922
static char * str_dup(const char * str)
 
923
{
 
924
    char * sdup = (char *) malloc(strlen(str) + 1);
 
925
 
 
926
    if (sdup)
 
927
        strcpy(sdup, str);
 
928
 
 
929
    return sdup;
 
930
}
 
931
 
 
932
/*
 
933
 *----------------------------------------------------------------------
 
934
 *
 
935
 * ClientAddrOK --
 
936
 *
 
937
 *      Checks if a client address is in a list of allowed addresses
 
938
 *
 
939
 * Results:
 
940
 *      TRUE if address list is empty or client address is present
 
941
 *      in the list, FALSE otherwise.
 
942
 *
 
943
 *----------------------------------------------------------------------
 
944
 */
 
945
static int ClientAddrOK(struct sockaddr_in *saPtr, const char *clientList)
 
946
{
 
947
    int result = FALSE;
 
948
    char *clientListCopy, *cur, *next;
 
949
 
 
950
    if (clientList == NULL || *clientList == '\0') {
 
951
        return TRUE;
 
952
    }
 
953
 
 
954
    clientListCopy = str_dup(clientList);
 
955
 
 
956
    for (cur = clientListCopy; cur != NULL; cur = next) {
 
957
        next = strchr(cur, ',');
 
958
        if (next != NULL) {
 
959
            *next++ = '\0';
 
960
        }
 
961
        if (inet_addr(cur) == saPtr->sin_addr.s_addr) {
 
962
            result = TRUE;
 
963
            break;
 
964
        }
 
965
    }
 
966
 
 
967
    free(clientListCopy);
 
968
    return result;
 
969
}
 
970
 
 
971
/*
 
972
 *----------------------------------------------------------------------
 
973
 *
 
974
 * AcquireLock --
 
975
 *
 
976
 *      On platforms that implement concurrent calls to accept
 
977
 *      on a shared listening ipcFd, returns 0.  On other platforms,
 
978
 *      acquires an exclusive lock across all processes sharing a
 
979
 *      listening ipcFd, blocking until the lock has been acquired.
 
980
 *
 
981
 * Results:
 
982
 *      0 for successful call, -1 in case of system error (fatal).
 
983
 *
 
984
 * Side effects:
 
985
 *      This process now has the exclusive lock.
 
986
 *
 
987
 *----------------------------------------------------------------------
 
988
 */
 
989
static int AcquireLock(int sock, int fail_on_intr)
 
990
{
 
991
#ifdef USE_LOCKING
 
992
    do {
 
993
        struct flock lock;
 
994
        lock.l_type = F_WRLCK;
 
995
        lock.l_start = 0;
 
996
        lock.l_whence = SEEK_SET;
 
997
        lock.l_len = 0;
 
998
 
 
999
        if (fcntl(sock, F_SETLKW, &lock) != -1)
 
1000
            return 0;
 
1001
    } while (errno == EINTR 
 
1002
             && ! fail_on_intr 
 
1003
             && ! shutdownPending);
 
1004
 
 
1005
    return -1;
 
1006
 
 
1007
#else
 
1008
    return 0;
 
1009
#endif
 
1010
}
 
1011
 
 
1012
/*
 
1013
 *----------------------------------------------------------------------
 
1014
 *
 
1015
 * ReleaseLock --
 
1016
 *
 
1017
 *      On platforms that implement concurrent calls to accept
 
1018
 *      on a shared listening ipcFd, does nothing.  On other platforms,
 
1019
 *      releases an exclusive lock acquired by AcquireLock.
 
1020
 *
 
1021
 * Results:
 
1022
 *      0 for successful call, -1 in case of system error (fatal).
 
1023
 *
 
1024
 * Side effects:
 
1025
 *      This process no longer holds the lock.
 
1026
 *
 
1027
 *----------------------------------------------------------------------
 
1028
 */
 
1029
static int ReleaseLock(int sock)
 
1030
{
 
1031
#ifdef USE_LOCKING
 
1032
    do {
 
1033
        struct flock lock;
 
1034
        lock.l_type = F_UNLCK;
 
1035
        lock.l_start = 0;
 
1036
        lock.l_whence = SEEK_SET;
 
1037
        lock.l_len = 0;
 
1038
 
 
1039
        if (fcntl(sock, F_SETLK, &lock) != -1)
 
1040
            return 0;
 
1041
    } while (errno == EINTR);
 
1042
 
 
1043
    return -1;
 
1044
 
 
1045
#else
 
1046
    return 0;
 
1047
#endif
 
1048
}
 
1049
 
 
1050
/**********************************************************************
 
1051
 * Determine if the errno resulting from a failed accept() warrants a
 
1052
 * retry or exit().  Based on Apache's http_main.c accept() handling
 
1053
 * and Stevens' Unix Network Programming Vol 1, 2nd Ed, para. 15.6.
 
1054
 */
 
1055
static int is_reasonable_accept_errno (const int error)
 
1056
{
 
1057
    switch (error) {
 
1058
#ifdef EPROTO
 
1059
        /* EPROTO on certain older kernels really means ECONNABORTED, so
 
1060
         * we need to ignore it for them.  See discussion in new-httpd
 
1061
         * archives nh.9701 search for EPROTO.  Also see nh.9603, search
 
1062
         * for EPROTO:  There is potentially a bug in Solaris 2.x x<6, and
 
1063
         * other boxes that implement tcp sockets in userland (i.e. on top of
 
1064
         * STREAMS).  On these systems, EPROTO can actually result in a fatal
 
1065
         * loop.  See PR#981 for example.  It's hard to handle both uses of
 
1066
         * EPROTO. */
 
1067
        case EPROTO:
 
1068
#endif
 
1069
#ifdef ECONNABORTED
 
1070
        case ECONNABORTED:
 
1071
#endif
 
1072
        /* Linux generates the rest of these, other tcp stacks (i.e.
 
1073
         * bsd) tend to hide them behind getsockopt() interfaces.  They
 
1074
         * occur when the net goes sour or the client disconnects after the
 
1075
         * three-way handshake has been done in the kernel but before
 
1076
         * userland has picked up the socket. */
 
1077
#ifdef ECONNRESET
 
1078
        case ECONNRESET:
 
1079
#endif
 
1080
#ifdef ETIMEDOUT
 
1081
        case ETIMEDOUT:
 
1082
#endif
 
1083
#ifdef EHOSTUNREACH
 
1084
        case EHOSTUNREACH:
 
1085
#endif
 
1086
#ifdef ENETUNREACH
 
1087
        case ENETUNREACH:
 
1088
#endif
 
1089
            return 1;
 
1090
 
 
1091
        default:
 
1092
            return 0;
 
1093
    }
 
1094
}
 
1095
 
 
1096
/**********************************************************************
 
1097
 * This works around a problem on Linux 2.0.x and SCO Unixware (maybe
 
1098
 * others?).  When a connect() is made to a Unix Domain socket, but its
 
1099
 * not accept()ed before the web server gets impatient and close()s, an
 
1100
 * accept() results in a valid file descriptor, but no data to read.
 
1101
 * This causes a block on the first read() - which never returns!
 
1102
 *
 
1103
 * Another approach to this is to write() to the socket to provoke a
 
1104
 * SIGPIPE, but this is a pain because of the FastCGI protocol, the fact
 
1105
 * that whatever is written has to be universally ignored by all FastCGI
 
1106
 * web servers, and a SIGPIPE handler has to be installed which returns
 
1107
 * (or SIGPIPE is ignored).
 
1108
 *
 
1109
 * READABLE_UNIX_FD_DROP_DEAD_TIMEVAL = 2,0 by default.
 
1110
 *
 
1111
 * Making it shorter is probably safe, but I'll leave that to you.  Making
 
1112
 * it 0,0 doesn't work reliably.  The shorter you can reliably make it,
 
1113
 * the faster your application will be able to recover (waiting 2 seconds
 
1114
 * may _cause_ the problem when there is a very high demand). At any rate,
 
1115
 * this is better than perma-blocking.
 
1116
 */
 
1117
static int is_af_unix_keeper(const int fd)
 
1118
{
 
1119
    struct timeval tval = { READABLE_UNIX_FD_DROP_DEAD_TIMEVAL };
 
1120
    fd_set read_fds;
 
1121
 
 
1122
    FD_ZERO(&read_fds);
 
1123
    FD_SET(fd, &read_fds);
 
1124
 
 
1125
    return select(fd + 1, &read_fds, NULL, NULL, &tval) >= 0 && FD_ISSET(fd, &read_fds);
 
1126
}
 
1127
 
 
1128
/*
 
1129
 *----------------------------------------------------------------------
 
1130
 *
 
1131
 * OS_Accept --
 
1132
 *
 
1133
 *      Accepts a new FastCGI connection.  This routine knows whether
 
1134
 *      we're dealing with TCP based sockets or NT Named Pipes for IPC.
 
1135
 *
 
1136
 * Results:
 
1137
 *      -1 if the operation fails, otherwise this is a valid IPC fd.
 
1138
 *
 
1139
 * Side effects:
 
1140
 *      New IPC connection is accepted.
 
1141
 *
 
1142
 *----------------------------------------------------------------------
 
1143
 */
 
1144
int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs)
 
1145
{
 
1146
    int socket = -1;
 
1147
    union {
 
1148
        struct sockaddr_un un;
 
1149
        struct sockaddr_in in;
 
1150
    } sa;
 
1151
 
 
1152
    for (;;) {
 
1153
        if (AcquireLock(listen_sock, fail_on_intr))
 
1154
            return -1;
 
1155
 
 
1156
        for (;;) {
 
1157
            do {
 
1158
#ifdef HAVE_SOCKLEN
 
1159
                socklen_t len = sizeof(sa);
 
1160
#else
 
1161
                int len = sizeof(sa);
 
1162
#endif
 
1163
                if (shutdownPending) break;
 
1164
                /* There's a window here */
 
1165
 
 
1166
                socket = accept(listen_sock, (struct sockaddr *)&sa, &len);
 
1167
            } while (socket < 0 
 
1168
                     && errno == EINTR 
 
1169
                     && ! fail_on_intr 
 
1170
                     && ! shutdownPending);
 
1171
 
 
1172
            if (socket < 0) {
 
1173
                if (shutdownPending || ! is_reasonable_accept_errno(errno)) {
 
1174
                    int errnoSave = errno;
 
1175
 
 
1176
                    ReleaseLock(listen_sock);
 
1177
                    
 
1178
                    if (! shutdownPending) {
 
1179
                        errno = errnoSave;
 
1180
                    }
 
1181
 
 
1182
                    return (-1);
 
1183
                }
 
1184
                errno = 0;
 
1185
            }
 
1186
            else {  /* socket >= 0 */
 
1187
                int set = 1;
 
1188
 
 
1189
                if (sa.in.sin_family != AF_INET)
 
1190
                    break;
 
1191
 
 
1192
#ifdef TCP_NODELAY
 
1193
                /* No replies to outgoing data, so disable Nagle */
 
1194
                setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *)&set, sizeof(set));
 
1195
#endif
 
1196
 
 
1197
                /* Check that the client IP address is approved */
 
1198
                if (ClientAddrOK(&sa.in, webServerAddrs))
 
1199
                    break;
 
1200
 
 
1201
                close(socket);
 
1202
            }  /* socket >= 0 */
 
1203
        }  /* for(;;) */
 
1204
 
 
1205
        if (ReleaseLock(listen_sock))
 
1206
            return (-1);
 
1207
 
 
1208
        if (sa.in.sin_family != AF_UNIX || is_af_unix_keeper(socket))
 
1209
            break;
 
1210
 
 
1211
        close(socket);
 
1212
    }  /* while(1) - lock */
 
1213
 
 
1214
    return (socket);
 
1215
}
 
1216
 
 
1217
/*
 
1218
 *----------------------------------------------------------------------
 
1219
 *
 
1220
 * OS_IpcClose
 
1221
 *
 
1222
 *      OS IPC routine to close an IPC connection.
 
1223
 *
 
1224
 * Results:
 
1225
 *
 
1226
 *
 
1227
 * Side effects:
 
1228
 *      IPC connection is closed.
 
1229
 *
 
1230
 *----------------------------------------------------------------------
 
1231
 */
 
1232
int OS_IpcClose(int ipcFd)
 
1233
{
 
1234
    return OS_Close(ipcFd);
 
1235
}
 
1236
 
 
1237
/*
 
1238
 *----------------------------------------------------------------------
 
1239
 *
 
1240
 * OS_IsFcgi --
 
1241
 *
 
1242
 *      Determines whether this process is a FastCGI process or not.
 
1243
 *
 
1244
 * Results:
 
1245
 *      Returns 1 if FastCGI, 0 if not.
 
1246
 *
 
1247
 * Side effects:
 
1248
 *      None.
 
1249
 *
 
1250
 *----------------------------------------------------------------------
 
1251
 */
 
1252
int OS_IsFcgi(int sock)
 
1253
{
 
1254
        union {
 
1255
        struct sockaddr_in in;
 
1256
        struct sockaddr_un un;
 
1257
    } sa;
 
1258
#ifdef HAVE_SOCKLEN
 
1259
    socklen_t len = sizeof(sa);
 
1260
#else
 
1261
    int len = sizeof(sa);
 
1262
#endif
 
1263
 
 
1264
    errno = 0;
 
1265
 
 
1266
    if (getpeername(sock, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) {
 
1267
        return TRUE;
 
1268
    }
 
1269
    else {
 
1270
        return FALSE;
 
1271
    }
 
1272
}
 
1273
 
 
1274
/*
 
1275
 *----------------------------------------------------------------------
 
1276
 *
 
1277
 * OS_SetFlags --
 
1278
 *
 
1279
 *      Sets selected flag bits in an open file descriptor.
 
1280
 *
 
1281
 *----------------------------------------------------------------------
 
1282
 */
 
1283
void OS_SetFlags(int fd, int flags)
 
1284
{
 
1285
    int val;
 
1286
    if((val = fcntl(fd, F_GETFL, 0)) < 0) {
 
1287
        exit(errno);
 
1288
    }
 
1289
    val |= flags;
 
1290
    if(fcntl(fd, F_SETFL, val) < 0) {
 
1291
        exit(errno);
 
1292
    }
 
1293
}