File: fdflag.c

package info (click to toggle)
lbcd 3.5.2-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 1,704 kB
  • ctags: 1,065
  • sloc: ansic: 11,073; sh: 1,823; perl: 503; makefile: 164
file content (152 lines) | stat: -rw-r--r-- 5,436 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
 * Set or clear file descriptor flags.
 *
 * Simple functions (wrappers around fcntl) to set or clear file descriptor
 * flags like close-on-exec or nonblocking I/O.
 *
 * The canonical version of this file is maintained in the rra-c-util package,
 * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
 *
 * Copyright 2008, 2011, 2013
 *     The Board of Trustees of the Leland Stanford Junior University
 * Copyright (c) 2004, 2005, 2006
 *     by Internet Systems Consortium, Inc. ("ISC")
 * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
 *     2002, 2003 by The Internet Software Consortium and Rich Salz
 *
 * This code is derived from software contributed to the Internet Software
 * Consortium by Rich Salz.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#include <config.h>
#include <portable/system.h>

#ifdef _WIN32
# include <winsock2.h>
#else
# include <fcntl.h>
# ifndef O_NONBLOCK
#  include <sys/ioctl.h>
#  if HAVE_SYS_FILIO_H
#   include <sys/filio.h>
#  endif
# endif
#endif

#include <util/fdflag.h>
#include <util/macros.h>


/*
 * Set a file to close-on-exec (or clear that setting if the flag is false),
 * returning true on success and false on failure.
 *
 * One is supposed to retrieve the flags, add FD_CLOEXEC, and then set them,
 * although I've never seen a system with any flags other than close-on-exec.
 * Do it right anyway; it's not that expensive.
 *
 * Stub this out on Windows, where it's not supported (at least currently by
 * this utility library).  Do not use socket_type for the first parameter,
 * since it's meaningful to set file descriptors for regular files to
 * close-on-exec (even though this is currently irrelevant since the function
 * isn't supported on Windows).
 */
#ifdef _WIN32
bool
fdflag_close_exec(int fd UNUSED, bool flag UNUSED)
{
    return false;
}
#else
bool
fdflag_close_exec(int fd, bool flag)
{
    int oflag, mode;

    oflag = fcntl(fd, F_GETFD, 0);
    if (oflag < 0)
        return false;
    mode = flag ? (oflag | FD_CLOEXEC) : (oflag & ~FD_CLOEXEC);
    return (fcntl(fd, F_SETFD, mode) == 0);
}
#endif


/*
 * Set a file descriptor to nonblocking (or clear the nonblocking flag if flag
 * is false), returning true on success and false on failure.
 *
 * For Windows, be aware that this will only work for sockets.  For UNIX, you
 * can pass a non-socket in and it will do the right thing, since UNIX doesn't
 * distinguish, but Windows will not allow that.  Thankfully, there's rarely
 * any need to set non-sockets non-blocking.
 *
 * For UNIX, always use O_NONBLOCK; O_NDELAY is not the same thing
 * historically.  The semantics of O_NDELAY are that if the read would block,
 * it returns 0 instead.  This is indistinguishable from an end of file
 * condition.  POSIX added O_NONBLOCK, which requires read to return -1 and
 * set errno to EAGAIN, which is what we want.
 *
 * FNDELAY (4.3BSD) originally did the correct thing, although it has a
 * different incompatibility (affecting all users of a socket rather than just
 * a file descriptor and returning EWOULDBLOCK instead of EAGAIN) that we
 * probably don't care about.  Using it is probably safe, but BSD should also
 * have the ioctl, and at least on Solaris FNDELAY does the same thing as
 * O_NDELAY, not O_NONBLOCK.  So if we don't have O_NONBLOCK, fall back to the
 * ioctl instead.
 *
 * Reference:  Stevens, Advanced Unix Programming, pg. 364.
 *
 * Note that O_NONBLOCK is known not to work on earlier versions of ULTRIX,
 * SunOS, and AIX, possibly not setting the socket nonblocking at all, despite
 * the fact that they do define it.  It works in later SunOS and, current AIX,
 * however, and a 1999-10-25 survey of current operating systems failed to
 * turn up any that didn't handle it correctly (as required by POSIX), while
 * HP-UX 11.00 did use the broken return-zero semantics of O_NDELAY (most
 * other operating systems surveyed treated O_NDELAY as synonymous with
 * O_NONBLOCK).  Accordingly, we currently unconditionally use O_NONBLOCK.  If
 * this causes too many problems, an autoconf test may be required.
 */
#if defined(_WIN32)
bool
fdflag_nonblocking(socket_type fd, bool flag)
{
    u_long mode;

    mode = flag ? 1 : 0;
    return (ioctlsocket(fd, FIONBIO, &mode) == 0);
}
#elif defined(O_NONBLOCK)
bool
fdflag_nonblocking(socket_type fd, bool flag)
{
    int mode;

    mode = fcntl(fd, F_GETFL, 0);
    if (mode < 0)
        return false;
    mode = (flag ? (mode | O_NONBLOCK) : (mode & ~O_NONBLOCK));
    return (fcntl(fd, F_SETFL, mode) == 0);
}
#else /* !O_NONBLOCK */
bool
fdflag_nonblocking(socket_type fd, bool flag)
{
    int state;

    state = flag ? 1 : 0;
    return (ioctl(fd, FIONBIO, &state) == 0);
}
#endif /* !O_NONBLOCK */